diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k')
22 files changed, 2368 insertions, 2095 deletions
diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile index cc09595b781a..2242a140e4fe 100644 --- a/drivers/net/wireless/ath/ath5k/Makefile +++ b/drivers/net/wireless/ath/ath5k/Makefile @@ -13,5 +13,6 @@ ath5k-y += base.o ath5k-y += led.o ath5k-y += rfkill.o ath5k-y += ani.o +ath5k-y += sysfs.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 index f2311ab35504..f1419198a479 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -74,8 +74,8 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level) 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); + ATH5K_ERR(ah->ah_sc, "noise immuniy level %d out of range", + level); return; } @@ -106,8 +106,8 @@ ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level) 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); + ATH5K_ERR(ah->ah_sc, "spur immunity level %d out of range", + level); return; } @@ -130,8 +130,7 @@ 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); + ATH5K_ERR(ah->ah_sc, "firstep level %d out of range", level); return; } @@ -356,41 +355,28 @@ ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) /** - * ath5k_hw_ani_get_listen_time() - Calculate time spent listening + * ath5k_hw_ani_get_listen_time() - Update counters and return listening time * * 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! + * since the last call of this function. + * Save a snapshot of the counter values for debugging/statistics. */ static int ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as) { + struct ath_common *common = ath5k_hw_common(ah); 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; + spin_lock_bh(&common->cc_lock); + + ath_hw_cycle_counters_update(common); + memcpy(&as->last_cc, &common->cc_ani, sizeof(as->last_cc)); + + /* clears common->cc_ani */ + listen = ath_hw_get_listen_time(common); + + spin_unlock_bh(&common->cc_lock); + return listen; } @@ -481,14 +467,15 @@ 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 */ + * might not have restarted the "ani period" last time. + * always do this to calculate the busy time also in manual mode */ listen = ath5k_hw_ani_get_listen_time(ah, as); as->listen_time += listen; + if (as->ani_mode != ATH5K_ANI_MODE_AUTO) + return; + ath5k_ani_save_and_clear_phy_errors(ah, as); ofdm_high = as->listen_time * ATH5K_ANI_OFDM_TRIG_HIGH / 1000; @@ -552,9 +539,9 @@ ath5k_ani_mib_intr(struct ath5k_hw *ah) 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 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; diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h index 55cf26d8522c..d0a664039c87 100644 --- a/drivers/net/wireless/ath/ath5k/ani.h +++ b/drivers/net/wireless/ath/ath5k/ani.h @@ -75,10 +75,7 @@ struct ath5k_ani_state { 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; + struct ath_cycle_counters last_cc; unsigned int last_listen; unsigned int last_ofdm_errors; unsigned int last_cck_errors; diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 2785946f659a..308b79e1ff08 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -175,7 +175,7 @@ #define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF 0 #define AR5K_TUNE_RADAR_ALERT false #define AR5K_TUNE_MIN_TX_FIFO_THRES 1 -#define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_LEN / 64) + 1) +#define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_FRAME_LEN / 64) + 1) #define AR5K_TUNE_REGISTER_TIMEOUT 20000 /* Register for RSSI threshold has a mask of 0xff, so 255 seems to * be the max value. */ @@ -204,6 +204,9 @@ #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 ATH5K_TUNE_CALIBRATION_INTERVAL_NF 60000 /* 60 sec */ + +#define ATH5K_TX_COMPLETE_POLL_INT 3000 /* 3 sec */ #define AR5K_INIT_CARR_SENSE_EN 1 @@ -255,8 +258,6 @@ (AR5K_INIT_PROG_IFS_TURBO) \ ) -/* token to use for aifs, cwmin, cwmax in MadWiFi */ -#define AR5K_TXQ_USEDEFAULT ((u32) -1) /* GENERIC CHIPSET DEFINITIONS */ @@ -342,15 +343,12 @@ struct ath5k_srev_name { #define AR5K_SREV_PHY_5413 0x61 #define AR5K_SREV_PHY_2425 0x70 -/* IEEE defs */ -#define IEEE80211_MAX_LEN 2500 - /* TODO add support to mac80211 for vendor-specific rates and modes */ /* * Some of this information is based on Documentation from: * - * http://madwifi.org/wiki/ChipsetFeatures/SuperAG + * http://madwifi-project.org/wiki/ChipsetFeatures/SuperAG * * Modulation for Atheros' eXtended Range - range enhancing extension that is * supposed to double the distance an Atheros client device can keep a @@ -530,9 +528,9 @@ struct ath5k_txq_info { enum ath5k_tx_queue tqi_type; enum ath5k_tx_queue_subtype tqi_subtype; u16 tqi_flags; /* Tx queue flags (see above) */ - u32 tqi_aifs; /* Arbitrated Interframe Space */ - s32 tqi_cw_min; /* Minimum Contention Window */ - s32 tqi_cw_max; /* Maximum Contention Window */ + u8 tqi_aifs; /* Arbitrated Interframe Space */ + u16 tqi_cw_min; /* Minimum Contention Window */ + u16 tqi_cw_max; /* Maximum Contention Window */ u32 tqi_cbr_period; /* Constant bit rate period */ u32 tqi_cbr_overflow_limit; u32 tqi_burst_time; @@ -565,7 +563,7 @@ enum ath5k_pkt_type { ) /* - * DMA size definitions (2^n+2) + * DMA size definitions (2^(n+2)) */ enum ath5k_dmasize { AR5K_DMASIZE_4B = 0, @@ -1030,8 +1028,6 @@ struct ath5k_hw { bool ah_turbo; bool ah_calibration; bool ah_single_chip; - bool ah_aes_support; - bool ah_combined_mic; enum ath5k_version ah_version; enum ath5k_radio ah_radio; @@ -1045,10 +1041,6 @@ struct ath5k_hw { #define ah_modes ah_capabilities.cap_mode #define ah_ee_version ah_capabilities.cap_eeprom.ee_version - u32 ah_atim_window; - u32 ah_aifs; - u32 ah_cw_min; - u32 ah_cw_max; u32 ah_limit_tx_retries; u8 ah_coverage_class; @@ -1118,6 +1110,7 @@ struct ath5k_hw { /* Calibration timestamp */ unsigned long ah_cal_next_full; unsigned long ah_cal_next_ani; + unsigned long ah_cal_next_nf; /* Calibration mask */ u8 ah_cal_mask; @@ -1125,15 +1118,10 @@ struct ath5k_hw { /* * Function pointers */ - int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc, - u32 size, unsigned int flags); int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, int, enum ath5k_pkt_type, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); - int (*ah_setup_mrr_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, - unsigned int, unsigned int, unsigned int, unsigned int, - unsigned int, unsigned int); int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, struct ath5k_tx_status *); int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *, @@ -1148,6 +1136,9 @@ struct ath5k_hw { int ath5k_hw_attach(struct ath5k_softc *sc); void ath5k_hw_detach(struct ath5k_hw *ah); +int ath5k_sysfs_register(struct ath5k_softc *sc); +void ath5k_sysfs_unregister(struct ath5k_softc *sc); + /* LED functions */ int ath5k_init_leds(struct ath5k_softc *sc); void ath5k_led_enable(struct ath5k_softc *sc); @@ -1190,7 +1181,7 @@ extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode); void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class); /* BSSID Functions */ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); -void ath5k_hw_set_associd(struct ath5k_hw *ah); +void ath5k_hw_set_bssid(struct ath5k_hw *ah); void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask); /* Receive start/stop functions */ void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah); @@ -1204,17 +1195,13 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah); void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64); void ath5k_hw_reset_tsf(struct ath5k_hw *ah); void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval); +bool ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval); /* ACK bit rate */ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high); /* Clock rate related functions */ unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec); unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock); -unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah); -/* Key table (WEP) functions */ -int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry); -int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, - const struct ieee80211_key_conf *key, const u8 *mac); -int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac); +void ath5k_hw_set_clockrate(struct ath5k_hw *ah); /* Queue Control Unit, DFS Control Unit Functions */ int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, @@ -1231,6 +1218,11 @@ int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time); /* Hardware Descriptor Functions */ int ath5k_hw_init_desc_functions(struct ath5k_hw *ah); +int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + u32 size, unsigned int flags); +int ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, + u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3); /* GPIO Functions */ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state); @@ -1270,6 +1262,7 @@ 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_update_noise_floor(struct ath5k_hw *ah); /* Spur mitigation */ bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, struct ieee80211_channel *channel); @@ -1280,6 +1273,7 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan); int ath5k_hw_phy_disable(struct ath5k_hw *ah); /* Antenna control */ void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode); +void ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode); /* TX power setup */ int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, u8 ee_mode, u8 txpower); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 31c008042bfe..fbe8aca975d8 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -118,9 +118,6 @@ int ath5k_hw_attach(struct ath5k_softc *sc) ah->ah_turbo = false; ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; ah->ah_imr = 0; - ah->ah_atim_window = 0; - ah->ah_aifs = AR5K_TUNE_AIFS; - ah->ah_cw_min = AR5K_TUNE_CWMIN; ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; ah->ah_software_retry = false; ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT; @@ -139,15 +136,15 @@ int ath5k_hw_attach(struct ath5k_softc *sc) else ah->ah_version = AR5K_AR5212; - /*Fill the ath5k_hw struct with the needed functions*/ + /* Fill the ath5k_hw struct with the needed functions */ ret = ath5k_hw_init_desc_functions(ah); if (ret) - goto err_free; + goto err; - /* Bring device out of sleep and reset it's units */ + /* Bring device out of sleep and reset its units */ ret = ath5k_hw_nic_wakeup(ah, 0, true); if (ret) - goto err_free; + goto err; /* Get MAC, PHY and RADIO revisions */ ah->ah_mac_srev = srev; @@ -158,7 +155,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) CHANNEL_5GHZ); ah->ah_phy = AR5K_PHY(0); - /* Try to identify radio chip based on it's srev */ + /* Try to identify radio chip based on its srev */ switch (ah->ah_radio_5ghz_revision & 0xf0) { case AR5K_SREV_RAD_5111: ah->ah_radio = AR5K_RF5111; @@ -237,7 +234,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) } else { ATH5K_ERR(sc, "Couldn't identify radio revision.\n"); ret = -ENODEV; - goto err_free; + goto err; } } @@ -247,7 +244,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) (srev < AR5K_SREV_AR2425)) { ATH5K_ERR(sc, "Device not yet supported.\n"); ret = -ENODEV; - goto err_free; + goto err; } /* @@ -255,7 +252,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) */ ret = ath5k_hw_post(ah); if (ret) - goto err_free; + goto err; /* Enable pci core retry fix on Hainan (5213A) and later chips */ if (srev >= AR5K_SREV_AR5213A) @@ -268,7 +265,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) ret = ath5k_eeprom_init(ah); if (ret) { ATH5K_ERR(sc, "unable to init EEPROM\n"); - goto err_free; + goto err; } ee = &ah->ah_capabilities.cap_eeprom; @@ -310,16 +307,20 @@ int ath5k_hw_attach(struct ath5k_softc *sc) if (ret) { ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n", sc->pdev->device); - goto err_free; + goto err; } /* Crypto settings */ - ah->ah_aes_support = srev >= AR5K_SREV_AR5212_V4 && - (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 && - !AR5K_EEPROM_AES_DIS(ee->ee_misc5)); + common->keymax = (sc->ah->ah_version == AR5K_AR5210 ? + AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211); + + if (srev >= AR5K_SREV_AR5212_V4 && + (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 && + !AR5K_EEPROM_AES_DIS(ee->ee_misc5))) + common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM; if (srev >= AR5K_SREV_AR2414) { - ah->ah_combined_mic = true; + common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE, AR5K_MISC_MODE_COMBINED_MIC); } @@ -329,7 +330,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN); - ath5k_hw_set_associd(ah); + ath5k_hw_set_bssid(ah); ath5k_hw_set_opmode(ah, sc->opmode); ath5k_hw_rfgain_opt_init(ah); @@ -340,8 +341,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) ath5k_hw_set_ledstate(ah, AR5K_LED_INIT); return 0; -err_free: - kfree(ah); +err: return ret; } @@ -352,8 +352,6 @@ err_free: */ void ath5k_hw_detach(struct ath5k_hw *ah) { - ATH5K_TRACE(ah->ah_sc); - __set_bit(ATH_STAT_INVALID, ah->ah_sc->status); if (ah->ah_rf_banks != NULL) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 648972df369d..8251946842e6 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -48,9 +48,11 @@ #include <linux/netdevice.h> #include <linux/cache.h> #include <linux/pci.h> +#include <linux/pci-aspm.h> #include <linux/ethtool.h> #include <linux/uaccess.h> #include <linux/slab.h> +#include <linux/etherdevice.h> #include <net/ieee80211_radiotap.h> @@ -60,6 +62,7 @@ #include "reg.h" #include "debug.h" #include "ani.h" +#include "../debug.h" static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); @@ -69,11 +72,6 @@ static int modparam_all_channels; module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO); MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); - -/******************\ -* Internal defines * -\******************/ - /* Module info */ MODULE_AUTHOR("Jiri Slaby"); MODULE_AUTHOR("Nick Kossifidis"); @@ -82,6 +80,10 @@ MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION("0.6.0 (EXPERIMENTAL)"); +static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan); +static int ath5k_beacon_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); +static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); /* Known PCI ids */ static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = { @@ -189,129 +191,7 @@ static const struct ieee80211_rate ath5k_rates[] = { /* XR missing */ }; -/* - * Prototypes - PCI stack related functions - */ -static int __devinit ath5k_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id); -static void __devexit ath5k_pci_remove(struct pci_dev *pdev); -#ifdef CONFIG_PM_SLEEP -static int ath5k_pci_suspend(struct device *dev); -static int ath5k_pci_resume(struct device *dev); - -static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume); -#define ATH5K_PM_OPS (&ath5k_pm_ops) -#else -#define ATH5K_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ - -static struct pci_driver ath5k_pci_driver = { - .name = KBUILD_MODNAME, - .id_table = ath5k_pci_id_table, - .probe = ath5k_pci_probe, - .remove = __devexit_p(ath5k_pci_remove), - .driver.pm = ATH5K_PM_OPS, -}; - - - -/* - * Prototypes - MAC 802.11 stack related functions - */ -static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb); -static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ath5k_txq *txq); -static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan); -static int ath5k_start(struct ieee80211_hw *hw); -static void ath5k_stop(struct ieee80211_hw *hw); -static int ath5k_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); -static void ath5k_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); -static int ath5k_config(struct ieee80211_hw *hw, u32 changed); -static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, - struct netdev_hw_addr_list *mc_list); -static void ath5k_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *new_flags, - u64 multicast); -static int ath5k_set_key(struct ieee80211_hw *hw, - enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key); -static int ath5k_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats); -static int ath5k_get_survey(struct ieee80211_hw *hw, - int idx, struct survey_info *survey); -static u64 ath5k_get_tsf(struct ieee80211_hw *hw); -static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); -static void ath5k_reset_tsf(struct ieee80211_hw *hw); -static int ath5k_beacon_update(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); -static void ath5k_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes); -static void ath5k_sw_scan_start(struct ieee80211_hw *hw); -static void ath5k_sw_scan_complete(struct ieee80211_hw *hw); -static void ath5k_set_coverage_class(struct ieee80211_hw *hw, - u8 coverage_class); - -static const struct ieee80211_ops ath5k_hw_ops = { - .tx = ath5k_tx, - .start = ath5k_start, - .stop = ath5k_stop, - .add_interface = ath5k_add_interface, - .remove_interface = ath5k_remove_interface, - .config = ath5k_config, - .prepare_multicast = ath5k_prepare_multicast, - .configure_filter = ath5k_configure_filter, - .set_key = ath5k_set_key, - .get_stats = ath5k_get_stats, - .get_survey = ath5k_get_survey, - .conf_tx = NULL, - .get_tsf = ath5k_get_tsf, - .set_tsf = ath5k_set_tsf, - .reset_tsf = ath5k_reset_tsf, - .bss_info_changed = ath5k_bss_info_changed, - .sw_scan_start = ath5k_sw_scan_start, - .sw_scan_complete = ath5k_sw_scan_complete, - .set_coverage_class = ath5k_set_coverage_class, -}; - -/* - * Prototypes - Internal functions - */ -/* Attach detach */ -static int ath5k_attach(struct pci_dev *pdev, - struct ieee80211_hw *hw); -static void ath5k_detach(struct pci_dev *pdev, - struct ieee80211_hw *hw); -/* Channel/mode setup */ -static inline short ath5k_ieee2mhz(short chan); -static unsigned int ath5k_copy_channels(struct ath5k_hw *ah, - struct ieee80211_channel *channels, - unsigned int mode, - unsigned int max); -static int ath5k_setup_bands(struct ieee80211_hw *hw); -static int ath5k_chan_set(struct ath5k_softc *sc, - struct ieee80211_channel *chan); -static void ath5k_setcurmode(struct ath5k_softc *sc, - unsigned int mode); -static void ath5k_mode_setup(struct ath5k_softc *sc); - -/* Descriptor setup */ -static int ath5k_desc_alloc(struct ath5k_softc *sc, - struct pci_dev *pdev); -static void ath5k_desc_free(struct ath5k_softc *sc, - struct pci_dev *pdev); -/* Buffers setup */ -static int ath5k_rxbuf_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf); -static int ath5k_txbuf_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf, - struct ath5k_txq *txq, int padsize); -static inline void ath5k_txbuf_free(struct ath5k_softc *sc, +static inline void ath5k_txbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf) { BUG_ON(!bf); @@ -321,9 +201,11 @@ static inline void ath5k_txbuf_free(struct ath5k_softc *sc, PCI_DMA_TODEVICE); dev_kfree_skb_any(bf->skb); bf->skb = NULL; + bf->skbaddr = 0; + bf->desc->ds_data = 0; } -static inline void ath5k_rxbuf_free(struct ath5k_softc *sc, +static inline void ath5k_rxbuf_free_skb(struct ath5k_softc *sc, struct ath5k_buf *bf) { struct ath5k_hw *ah = sc->ah; @@ -336,39 +218,11 @@ static inline void ath5k_rxbuf_free(struct ath5k_softc *sc, PCI_DMA_FROMDEVICE); dev_kfree_skb_any(bf->skb); bf->skb = NULL; + bf->skbaddr = 0; + bf->desc->ds_data = 0; } -/* Queues setup */ -static struct ath5k_txq *ath5k_txq_setup(struct ath5k_softc *sc, - int qtype, int subtype); -static int ath5k_beaconq_setup(struct ath5k_hw *ah); -static int ath5k_beaconq_config(struct ath5k_softc *sc); -static void ath5k_txq_drainq(struct ath5k_softc *sc, - struct ath5k_txq *txq); -static void ath5k_txq_cleanup(struct ath5k_softc *sc); -static void ath5k_txq_release(struct ath5k_softc *sc); -/* Rx handling */ -static int ath5k_rx_start(struct ath5k_softc *sc); -static void ath5k_rx_stop(struct ath5k_softc *sc); -static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc, - struct ath5k_desc *ds, - struct sk_buff *skb, - struct ath5k_rx_status *rs); -static void ath5k_tasklet_rx(unsigned long data); -/* Tx handling */ -static void ath5k_tx_processq(struct ath5k_softc *sc, - struct ath5k_txq *txq); -static void ath5k_tasklet_tx(unsigned long data); -/* Beacon handling */ -static int ath5k_beacon_setup(struct ath5k_softc *sc, - struct ath5k_buf *bf); -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) { u64 tsf = ath5k_hw_get_tsf64(ah); @@ -379,50 +233,6 @@ static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) return (tsf & ~0x7fff) | rstamp; } -/* Interrupt handling */ -static int ath5k_init(struct ath5k_softc *sc); -static int ath5k_stop_locked(struct ath5k_softc *sc); -static int ath5k_stop_hw(struct ath5k_softc *sc); -static irqreturn_t ath5k_intr(int irq, void *dev_id); -static void ath5k_tasklet_reset(unsigned long data); - -static void ath5k_tasklet_calibrate(unsigned long data); - -/* - * Module init/exit functions - */ -static int __init -init_ath5k_pci(void) -{ - int ret; - - ath5k_debug_init(); - - ret = pci_register_driver(&ath5k_pci_driver); - if (ret) { - printk(KERN_ERR "ath5k_pci: can't register pci driver\n"); - return ret; - } - - return 0; -} - -static void __exit -exit_ath5k_pci(void) -{ - pci_unregister_driver(&ath5k_pci_driver); - - ath5k_debug_finish(); -} - -module_init(init_ath5k_pci); -module_exit(exit_ath5k_pci); - - -/********************\ -* PCI Initialization * -\********************/ - static const char * ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val) { @@ -461,282 +271,6 @@ static const struct ath_ops ath5k_common_ops = { .write = ath5k_iowrite32, }; -static int __devinit -ath5k_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - void __iomem *mem; - struct ath5k_softc *sc; - struct ath_common *common; - struct ieee80211_hw *hw; - int ret; - u8 csz; - - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, "can't enable device\n"); - goto err; - } - - /* XXX 32-bit addressing only */ - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) { - dev_err(&pdev->dev, "32-bit DMA not available\n"); - goto err_dis; - } - - /* - * Cache line size is used to size and align various - * structures used to communicate with the hardware. - */ - pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); - if (csz == 0) { - /* - * Linux 2.4.18 (at least) writes the cache line size - * register as a 16-bit wide register which is wrong. - * We must have this setup properly for rx buffer - * DMA to work so force a reasonable value here if it - * comes up zero. - */ - csz = L1_CACHE_BYTES >> 2; - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); - } - /* - * The default setting of latency timer yields poor results, - * set it to the value used by other systems. It may be worth - * tweaking this setting more. - */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); - - /* Enable bus mastering */ - pci_set_master(pdev); - - /* - * Disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state. - */ - pci_write_config_byte(pdev, 0x41, 0); - - ret = pci_request_region(pdev, 0, "ath5k"); - if (ret) { - dev_err(&pdev->dev, "cannot reserve PCI memory region\n"); - goto err_dis; - } - - mem = pci_iomap(pdev, 0, 0); - if (!mem) { - dev_err(&pdev->dev, "cannot remap PCI memory region\n") ; - ret = -EIO; - goto err_reg; - } - - /* - * Allocate hw (mac80211 main struct) - * and hw->priv (driver private data) - */ - hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops); - if (hw == NULL) { - dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n"); - ret = -ENOMEM; - goto err_map; - } - - dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy)); - - /* Initialize driver private data */ - SET_IEEE80211_DEV(hw, &pdev->dev); - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM; - - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_MESH_POINT); - - hw->extra_tx_headroom = 2; - hw->channel_change_time = 5000; - sc = hw->priv; - sc->hw = hw; - sc->pdev = pdev; - - ath5k_debug_init_device(sc); - - /* - * Mark the device as detached to avoid processing - * interrupts until setup is complete. - */ - __set_bit(ATH_STAT_INVALID, sc->status); - - sc->iobase = mem; /* So we can unmap it on detach */ - sc->opmode = NL80211_IFTYPE_STATION; - sc->bintval = 1000; - mutex_init(&sc->lock); - spin_lock_init(&sc->rxbuflock); - spin_lock_init(&sc->txbuflock); - spin_lock_init(&sc->block); - - /* Set private data */ - pci_set_drvdata(pdev, hw); - - /* Setup interrupt handler */ - ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); - if (ret) { - ATH5K_ERR(sc, "request_irq failed\n"); - goto err_free; - } - - /*If we passed the test malloc a ath5k_hw struct*/ - sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL); - if (!sc->ah) { - ret = -ENOMEM; - ATH5K_ERR(sc, "out of memory\n"); - goto err_irq; - } - - sc->ah->ah_sc = sc; - sc->ah->ah_iobase = sc->iobase; - common = ath5k_hw_common(sc->ah); - common->ops = &ath5k_common_ops; - common->ah = sc->ah; - common->hw = hw; - common->cachelsz = csz << 2; /* convert to bytes */ - - /* Initialize device */ - ret = ath5k_hw_attach(sc); - if (ret) { - goto err_free_ah; - } - - /* set up multi-rate retry capabilities */ - if (sc->ah->ah_version == AR5K_AR5212) { - hw->max_rates = 4; - hw->max_rate_tries = 11; - } - - /* Finish private driver data initialization */ - ret = ath5k_attach(pdev, hw); - if (ret) - goto err_ah; - - ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n", - ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev), - sc->ah->ah_mac_srev, - sc->ah->ah_phy_revision); - - if (!sc->ah->ah_single_chip) { - /* Single chip radio (!RF5111) */ - if (sc->ah->ah_radio_5ghz_revision && - !sc->ah->ah_radio_2ghz_revision) { - /* No 5GHz support -> report 2GHz radio */ - if (!test_bit(AR5K_MODE_11A, - sc->ah->ah_capabilities.cap_mode)) { - ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); - /* No 2GHz support (5110 and some - * 5Ghz only cards) -> report 5Ghz radio */ - } else if (!test_bit(AR5K_MODE_11B, - sc->ah->ah_capabilities.cap_mode)) { - ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); - /* Multiband radio */ - } else { - ATH5K_INFO(sc, "RF%s multiband radio found" - " (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); - } - } - /* Multi chip radio (RF5111 - RF2111) -> - * report both 2GHz/5GHz radios */ - else if (sc->ah->ah_radio_5ghz_revision && - sc->ah->ah_radio_2ghz_revision){ - ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_5ghz_revision), - sc->ah->ah_radio_5ghz_revision); - ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", - ath5k_chip_name(AR5K_VERSION_RAD, - sc->ah->ah_radio_2ghz_revision), - sc->ah->ah_radio_2ghz_revision); - } - } - - - /* ready to process interrupts */ - __clear_bit(ATH_STAT_INVALID, sc->status); - - return 0; -err_ah: - ath5k_hw_detach(sc->ah); -err_irq: - free_irq(pdev->irq, sc); -err_free_ah: - kfree(sc->ah); -err_free: - ieee80211_free_hw(hw); -err_map: - pci_iounmap(pdev, mem); -err_reg: - pci_release_region(pdev, 0); -err_dis: - pci_disable_device(pdev); -err: - return ret; -} - -static void __devexit -ath5k_pci_remove(struct pci_dev *pdev) -{ - struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath5k_softc *sc = hw->priv; - - ath5k_debug_finish_device(sc); - ath5k_detach(pdev, hw); - ath5k_hw_detach(sc->ah); - kfree(sc->ah); - free_irq(pdev->irq, sc); - pci_iounmap(pdev, sc->iobase); - pci_release_region(pdev, 0); - pci_disable_device(pdev); - ieee80211_free_hw(hw); -} - -#ifdef CONFIG_PM_SLEEP -static int ath5k_pci_suspend(struct device *dev) -{ - struct ieee80211_hw *hw = pci_get_drvdata(to_pci_dev(dev)); - struct ath5k_softc *sc = hw->priv; - - ath5k_led_off(sc); - return 0; -} - -static int ath5k_pci_resume(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct ieee80211_hw *hw = pci_get_drvdata(pdev); - struct ath5k_softc *sc = hw->priv; - - /* - * Suspend/Resume resets the PCI configuration space, so we have to - * re-disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state - */ - pci_write_config_byte(pdev, 0x41, 0); - - ath5k_led_enable(sc); - return 0; -} -#endif /* CONFIG_PM_SLEEP */ - - /***********************\ * Driver Initialization * \***********************/ @@ -750,165 +284,6 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re return ath_reg_notifier_apply(wiphy, request, regulatory); } -static int -ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) -{ - struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; - struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah); - u8 mac[ETH_ALEN] = {}; - int ret; - - ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); - - /* - * Check if the MAC has multi-rate retry support. - * We do this by trying to setup a fake extended - * descriptor. MAC's that don't have support will - * return false w/o doing anything. MAC's that do - * support it will return true w/o doing anything. - */ - ret = ah->ah_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0); - if (ret < 0) - goto err; - if (ret > 0) - __set_bit(ATH_STAT_MRRETRY, sc->status); - - /* - * Collect the channel list. The 802.11 layer - * is resposible for filtering this list based - * on settings like the phy mode and regulatory - * domain restrictions. - */ - ret = ath5k_setup_bands(hw); - if (ret) { - ATH5K_ERR(sc, "can't get channels\n"); - goto err; - } - - /* NB: setup here so ath5k_rate_update is happy */ - if (test_bit(AR5K_MODE_11A, ah->ah_modes)) - ath5k_setcurmode(sc, AR5K_MODE_11A); - else - ath5k_setcurmode(sc, AR5K_MODE_11B); - - /* - * Allocate tx+rx descriptors and populate the lists. - */ - ret = ath5k_desc_alloc(sc, pdev); - if (ret) { - ATH5K_ERR(sc, "can't allocate descriptors\n"); - goto err; - } - - /* - * Allocate hardware transmit queues: one queue for - * beacon frames and one data queue for each QoS - * priority. Note that hw functions handle reseting - * these queues at the needed time. - */ - ret = ath5k_beaconq_setup(ah); - if (ret < 0) { - ATH5K_ERR(sc, "can't setup a beacon xmit queue\n"); - goto err_desc; - } - sc->bhalq = ret; - sc->cabq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0); - if (IS_ERR(sc->cabq)) { - ATH5K_ERR(sc, "can't setup cab queue\n"); - ret = PTR_ERR(sc->cabq); - goto err_bhal; - } - - sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK); - if (IS_ERR(sc->txq)) { - ATH5K_ERR(sc, "can't setup xmit queue\n"); - ret = PTR_ERR(sc->txq); - goto err_queues; - } - - tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); - tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); - 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) { - ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", - sc->pdev->device); - goto err_queues; - } - - SET_IEEE80211_PERM_ADDR(hw, mac); - /* All MAC address bits matter for ACKs */ - memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN); - ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); - - regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; - ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); - if (ret) { - ATH5K_ERR(sc, "can't initialize regulatory system\n"); - goto err_queues; - } - - ret = ieee80211_register_hw(hw); - if (ret) { - ATH5K_ERR(sc, "can't register ieee80211 hw\n"); - goto err_queues; - } - - if (!ath_is_world_regd(regulatory)) - regulatory_hint(hw->wiphy, regulatory->alpha2); - - ath5k_init_leds(sc); - - return 0; -err_queues: - ath5k_txq_release(sc); -err_bhal: - ath5k_hw_release_tx_queue(ah, sc->bhalq); -err_desc: - ath5k_desc_free(sc, pdev); -err: - return ret; -} - -static void -ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw) -{ - struct ath5k_softc *sc = hw->priv; - - /* - * NB: the order of these is important: - * o call the 802.11 layer before detaching ath5k_hw to - * insure callbacks into the driver to delete global - * key cache entries can be handled - * o reclaim the tx queue data structures after calling - * the 802.11 layer as we'll get called back to reclaim - * node state and potentially want to use them - * o to cleanup the tx queues the hal is called, so detach - * it last - * XXX: ??? detach ath5k_hw ??? - * Other than that, it's straightforward... - */ - ieee80211_unregister_hw(hw); - ath5k_desc_free(sc, pdev); - ath5k_txq_release(sc); - ath5k_hw_release_tx_queue(sc->ah, sc->bhalq); - ath5k_unregister_leds(sc); - - /* - * NB: can't reclaim these until after ieee80211_ifdetach - * returns because we'll get called back to reclaim node - * state and potentially want to use them. - */ -} - - - - /********************\ * Channel/mode setup * \********************/ @@ -1111,8 +486,9 @@ ath5k_setup_bands(struct ieee80211_hw *hw) static int ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) { - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n", - sc->curchan->center_freq, chan->center_freq); + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, + "channel set, resetting (%u -> %u MHz)\n", + sc->curchan->center_freq, chan->center_freq); /* * To switch channels clear any pending DMA operations; @@ -1135,8 +511,101 @@ ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) } } +struct ath_vif_iter_data { + const u8 *hw_macaddr; + u8 mask[ETH_ALEN]; + u8 active_mac[ETH_ALEN]; /* first active MAC */ + bool need_set_hw_addr; + bool found_active; + bool any_assoc; + enum nl80211_iftype opmode; +}; + +static void ath_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_vif_iter_data *iter_data = data; + int i; + struct ath5k_vif *avf = (void *)vif->drv_priv; + + if (iter_data->hw_macaddr) + for (i = 0; i < ETH_ALEN; i++) + iter_data->mask[i] &= + ~(iter_data->hw_macaddr[i] ^ mac[i]); + + if (!iter_data->found_active) { + iter_data->found_active = true; + memcpy(iter_data->active_mac, mac, ETH_ALEN); + } + + if (iter_data->need_set_hw_addr && iter_data->hw_macaddr) + if (compare_ether_addr(iter_data->hw_macaddr, mac) == 0) + iter_data->need_set_hw_addr = false; + + if (!iter_data->any_assoc) { + if (avf->assoc) + iter_data->any_assoc = true; + } + + /* Calculate combined mode - when APs are active, operate in AP mode. + * Otherwise use the mode of the new interface. This can currently + * only deal with combinations of APs and STAs. Only one ad-hoc + * interfaces is allowed above. + */ + if (avf->opmode == NL80211_IFTYPE_AP) + iter_data->opmode = NL80211_IFTYPE_AP; + else + if (iter_data->opmode == NL80211_IFTYPE_UNSPECIFIED) + iter_data->opmode = avf->opmode; +} + +static void ath_do_set_opmode(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + ath5k_hw_set_opmode(ah, sc->opmode); + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d (%s)\n", + sc->opmode, ath_opmode_to_string(sc->opmode)); +} + +void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc, + struct ieee80211_vif *vif) +{ + struct ath_common *common = ath5k_hw_common(sc->ah); + struct ath_vif_iter_data iter_data; + + /* + * Use the hardware MAC address as reference, the hardware uses it + * together with the BSSID mask when matching addresses. + */ + iter_data.hw_macaddr = common->macaddr; + memset(&iter_data.mask, 0xff, ETH_ALEN); + iter_data.found_active = false; + iter_data.need_set_hw_addr = true; + iter_data.opmode = NL80211_IFTYPE_UNSPECIFIED; + + if (vif) + ath_vif_iter(&iter_data, vif->addr, vif); + + /* Get list of all active MAC addresses */ + ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter, + &iter_data); + memcpy(sc->bssidmask, iter_data.mask, ETH_ALEN); + + sc->opmode = iter_data.opmode; + if (sc->opmode == NL80211_IFTYPE_UNSPECIFIED) + /* Nothing active, default to station mode */ + sc->opmode = NL80211_IFTYPE_STATION; + + ath_do_set_opmode(sc); + + if (iter_data.need_set_hw_addr && iter_data.found_active) + ath5k_hw_set_lladdr(sc->ah, iter_data.active_mac); + + if (ath5k_hw_hasbssidmask(sc->ah)) + ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); +} + static void -ath5k_mode_setup(struct ath5k_softc *sc) +ath5k_mode_setup(struct ath5k_softc *sc, struct ieee80211_vif *vif) { struct ath5k_hw *ah = sc->ah; u32 rfilt; @@ -1144,15 +613,9 @@ ath5k_mode_setup(struct ath5k_softc *sc) /* configure rx filter */ rfilt = sc->filter_flags; ath5k_hw_set_rx_filter(ah, rfilt); - - if (ath5k_hw_hasbssidmask(ah)) - ath5k_hw_set_bssid_mask(ah, sc->bssidmask); - - /* configure operational mode */ - ath5k_hw_set_opmode(ah, sc->opmode); - - ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d\n", sc->opmode); ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); + + ath5k_update_bssid_mask_and_opmode(sc, vif); } static inline int @@ -1228,21 +691,23 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) * not get overrun under high load (as can happen with a * 5212 when ANI processing enables PHY error frames). * - * To insure the last descriptor is self-linked we create + * To ensure the last descriptor is self-linked we create * each descriptor as self-linked and add it to the end. As * each additional descriptor is added the previous self-linked - * entry is ``fixed'' naturally. This should be safe even + * entry is "fixed" naturally. This should be safe even * if DMA is happening. When processing RX interrupts we * never remove/process the last, self-linked, entry on the - * descriptor list. This insures the hardware always has + * descriptor list. This ensures the hardware always has * someplace to write a new frame. */ ds = bf->desc; ds->ds_link = bf->daddr; /* link to self */ ds->ds_data = bf->skbaddr; - ret = ah->ah_setup_rx_desc(ah, ds, ah->common.rx_bufsize, 0); - if (ret) + ret = ath5k_hw_setup_rx_desc(ah, ds, ah->common.rx_bufsize, 0); + if (ret) { + ATH5K_ERR(sc, "%s: could not setup RX desc\n", __func__); return ret; + } if (sc->rxlink != NULL) *sc->rxlink = bf->daddr; @@ -1297,6 +762,10 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, PCI_DMA_TODEVICE); rate = ieee80211_get_tx_rate(sc->hw, info); + if (!rate) { + ret = -EINVAL; + goto err_unmap; + } if (info->flags & IEEE80211_TX_CTL_NO_ACK) flags |= AR5K_TXDESC_NOACK; @@ -1318,13 +787,13 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, flags |= AR5K_TXDESC_RTSENA; cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; duration = le16_to_cpu(ieee80211_rts_duration(sc->hw, - sc->vif, pktlen, info)); + info->control.vif, pktlen, info)); } if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { flags |= AR5K_TXDESC_CTSENA; cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw, - sc->vif, pktlen, info)); + info->control.vif, pktlen, info)); } ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), padsize, @@ -1347,7 +816,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, mrr_tries[i] = info->control.rates[i + 1].count; } - ah->ah_setup_mrr_tx_desc(ah, ds, + ath5k_hw_setup_mrr_tx_desc(ah, ds, mrr_rate[0], mrr_tries[0], mrr_rate[1], mrr_tries[1], mrr_rate[2], mrr_tries[2]); @@ -1357,6 +826,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, spin_lock_bh(&txq->lock); list_add_tail(&bf->list, &txq->q); + txq->txq_len++; if (txq->link == NULL) /* is this first packet? */ ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr); else /* no, so only link it */ @@ -1425,10 +895,13 @@ ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev) list_add_tail(&bf->list, &sc->txbuf); } - /* beacon buffer */ - bf->desc = ds; - bf->daddr = da; - sc->bbuf = bf; + /* beacon buffers */ + INIT_LIST_HEAD(&sc->bcbuf); + for (i = 0; i < ATH_BCBUF; i++, bf++, ds++, da += sizeof(*ds)) { + bf->desc = ds; + bf->daddr = da; + list_add_tail(&bf->list, &sc->bcbuf); + } return 0; err_free: @@ -1443,23 +916,23 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev) { struct ath5k_buf *bf; - ath5k_txbuf_free(sc, sc->bbuf); list_for_each_entry(bf, &sc->txbuf, list) - ath5k_txbuf_free(sc, bf); + ath5k_txbuf_free_skb(sc, bf); list_for_each_entry(bf, &sc->rxbuf, list) - ath5k_rxbuf_free(sc, bf); + ath5k_rxbuf_free_skb(sc, bf); + list_for_each_entry(bf, &sc->bcbuf, list) + ath5k_txbuf_free_skb(sc, bf); /* Free memory associated with all descriptors */ pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); + sc->desc = NULL; + sc->desc_daddr = 0; kfree(sc->bufptr); sc->bufptr = NULL; } - - - /**************\ * Queues setup * \**************/ @@ -1472,16 +945,18 @@ ath5k_txq_setup(struct ath5k_softc *sc, struct ath5k_txq *txq; struct ath5k_txq_info qi = { .tqi_subtype = subtype, - .tqi_aifs = AR5K_TXQ_USEDEFAULT, - .tqi_cw_min = AR5K_TXQ_USEDEFAULT, - .tqi_cw_max = AR5K_TXQ_USEDEFAULT + /* XXX: default values not correct for B and XR channels, + * but who cares? */ + .tqi_aifs = AR5K_TUNE_AIFS, + .tqi_cw_min = AR5K_TUNE_CWMIN, + .tqi_cw_max = AR5K_TUNE_CWMAX }; int qnum; /* * Enable interrupts only for EOL and DESC conditions. * We mark tx descriptors to receive a DESC interrupt - * when a tx queue gets deep; otherwise waiting for the + * when a tx queue gets deep; otherwise we wait for the * EOL to reap descriptors. Note that this is done to * reduce interrupt load and this only defers reaping * descriptors, never transmitting frames. Aside from @@ -1513,6 +988,9 @@ ath5k_txq_setup(struct ath5k_softc *sc, INIT_LIST_HEAD(&txq->q); spin_lock_init(&txq->lock); txq->setup = true; + txq->txq_len = 0; + txq->txq_poll_mark = false; + txq->txq_stuck = 0; } return &sc->txqs[qnum]; } @@ -1521,9 +999,11 @@ static int ath5k_beaconq_setup(struct ath5k_hw *ah) { struct ath5k_txq_info qi = { - .tqi_aifs = AR5K_TXQ_USEDEFAULT, - .tqi_cw_min = AR5K_TXQ_USEDEFAULT, - .tqi_cw_max = AR5K_TXQ_USEDEFAULT, + /* XXX: default values not correct for B and XR channels, + * but who cares? */ + .tqi_aifs = AR5K_TUNE_AIFS, + .tqi_cw_min = AR5K_TUNE_CWMIN, + .tqi_cw_max = AR5K_TUNE_CWMAX, /* NB: for dynamic turbo, don't enable any other interrupts */ .tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE }; @@ -1557,7 +1037,7 @@ ath5k_beaconq_config(struct ath5k_softc *sc) */ qi.tqi_aifs = 0; qi.tqi_cw_min = 0; - qi.tqi_cw_max = 2 * ah->ah_cw_min; + qi.tqi_cw_max = 2 * AR5K_TUNE_CWMIN; } ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, @@ -1602,14 +1082,16 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) list_for_each_entry_safe(bf, bf0, &txq->q, list) { ath5k_debug_printtxbuf(sc, bf); - ath5k_txbuf_free(sc, bf); + ath5k_txbuf_free_skb(sc, bf); spin_lock_bh(&sc->txbuflock); list_move_tail(&bf->list, &sc->txbuf); sc->txbuf_len++; + txq->txq_len--; spin_unlock_bh(&sc->txbuflock); } txq->link = NULL; + txq->txq_poll_mark = false; spin_unlock_bh(&txq->lock); } @@ -1659,8 +1141,6 @@ ath5k_txq_release(struct ath5k_softc *sc) } - - /*************\ * RX Handling * \*************/ @@ -1676,7 +1156,7 @@ ath5k_rx_start(struct ath5k_softc *sc) struct ath5k_buf *bf; int ret; - common->rx_bufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz); + common->rx_bufsize = roundup(IEEE80211_MAX_FRAME_LEN, common->cachelsz); ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rx_bufsize %u\n", common->cachelsz, common->rx_bufsize); @@ -1695,7 +1175,7 @@ ath5k_rx_start(struct ath5k_softc *sc) spin_unlock_bh(&sc->rxbuflock); ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */ - ath5k_mode_setup(sc); /* set filters, etc. */ + ath5k_mode_setup(sc, NULL); /* set filters, etc. */ ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */ return 0; @@ -1716,13 +1196,11 @@ ath5k_rx_stop(struct ath5k_softc *sc) ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */ ath5k_debug_printrxbuffs(sc, ah); - - sc->rxlink = NULL; /* just in case */ } static unsigned int -ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, - struct sk_buff *skb, struct ath5k_rx_status *rs) +ath5k_rx_decrypted(struct ath5k_softc *sc, struct sk_buff *skb, + struct ath5k_rx_status *rs) { struct ath5k_hw *ah = sc->ah; struct ath_common *common = ath5k_hw_common(ah); @@ -1805,6 +1283,15 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, */ if (hw_tu >= sc->nexttbtt) ath5k_beacon_update_timers(sc, bc_tstamp); + + /* Check if the beacon timers are still correct, because a TSF + * update might have created a window between them - for a + * longer description see the comment of this function: */ + if (!ath5k_hw_check_beacon_timers(sc->ah, sc->bintval)) { + ath5k_beacon_update_timers(sc, bc_tstamp); + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "fixed beacon timers after beacon receive\n"); + } } } @@ -1828,7 +1315,7 @@ ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi) } /* - * Compute padding position. skb must contains an IEEE 802.11 frame + * Compute padding position. skb must contain an IEEE 802.11 frame */ static int ath5k_common_padpos(struct sk_buff *skb) { @@ -1847,10 +1334,9 @@ static int ath5k_common_padpos(struct sk_buff *skb) } /* - * This function expects a 802.11 frame and returns the number of - * bytes added, or -1 if we don't have enought header room. + * This function expects an 802.11 frame and returns the number of + * bytes added, or -1 if we don't have enough header room. */ - static int ath5k_add_padding(struct sk_buff *skb) { int padpos = ath5k_common_padpos(skb); @@ -1870,10 +1356,18 @@ static int ath5k_add_padding(struct sk_buff *skb) } /* - * This function expects a 802.11 frame and returns the number of - * bytes removed + * The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = 4 - (hdrlen & 3); however, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. We must not try to + * remove padding from short control frames that do not have a + * payload. + * + * This function expects an 802.11 frame and returns the number of + * bytes removed. */ - static int ath5k_remove_padding(struct sk_buff *skb) { int padpos = ath5k_common_padpos(skb); @@ -1889,9 +1383,130 @@ static int ath5k_remove_padding(struct sk_buff *skb) } static void -ath5k_tasklet_rx(unsigned long data) +ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb, + struct ath5k_rx_status *rs) { struct ieee80211_rx_status *rxs; + + ath5k_remove_padding(skb); + + rxs = IEEE80211_SKB_RXCB(skb); + + rxs->flag = 0; + if (unlikely(rs->rs_status & AR5K_RXERR_MIC)) + rxs->flag |= RX_FLAG_MMIC_ERROR; + + /* + * always extend the mac timestamp, since this information is + * also needed for proper IBSS merging. + * + * XXX: it might be too late to do it here, since rs_tstamp is + * 15bit only. that means TSF extension has to be done within + * 32768usec (about 32ms). it might be necessary to move this to + * the interrupt handler, like it is done in madwifi. + * + * Unfortunately we don't know when the hardware takes the rx + * timestamp (beginning of phy frame, data frame, end of rx?). + * The only thing we know is that it is hardware specific... + * On AR5213 it seems the rx timestamp is at the end of the + * frame, but i'm not sure. + * + * NOTE: mac80211 defines mactime at the beginning of the first + * data symbol. Since we don't have any time references it's + * impossible to comply to that. This affects IBSS merge only + * right now, so it's not too bad... + */ + rxs->mactime = ath5k_extend_tsf(sc->ah, rs->rs_tstamp); + rxs->flag |= RX_FLAG_TSFT; + + rxs->freq = sc->curchan->center_freq; + rxs->band = sc->curband->band; + + rxs->signal = sc->ah->ah_noise_floor + rs->rs_rssi; + + rxs->antenna = rs->rs_antenna; + + if (rs->rs_antenna > 0 && rs->rs_antenna < 5) + sc->stats.antenna_rx[rs->rs_antenna]++; + else + sc->stats.antenna_rx[0]++; /* invalid */ + + rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs->rs_rate); + rxs->flag |= ath5k_rx_decrypted(sc, skb, rs); + + if (rxs->rate_idx >= 0 && rs->rs_rate == + sc->curband->bitrates[rxs->rate_idx].hw_value_short) + rxs->flag |= RX_FLAG_SHORTPRE; + + 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); + + ieee80211_rx(sc->hw, skb); +} + +/** ath5k_frame_receive_ok() - Do we want to receive this frame or not? + * + * Check if we want to further process this frame or not. Also update + * statistics. Return true if we want this frame, false if not. + */ +static bool +ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs) +{ + sc->stats.rx_all_count++; + sc->stats.rx_bytes_count += rs->rs_datalen; + + if (unlikely(rs->rs_status)) { + if (rs->rs_status & AR5K_RXERR_CRC) + sc->stats.rxerr_crc++; + if (rs->rs_status & AR5K_RXERR_FIFO) + 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]++; + return false; + } + if (rs->rs_status & AR5K_RXERR_DECRYPT) { + /* + * Decrypt error. If the error occurred + * because there was no hardware key, then + * let the frame through so the upper layers + * can process it. This is necessary for 5210 + * parts which have no way to setup a ``clear'' + * key cache entry. + * + * XXX do key cache faulting + */ + sc->stats.rxerr_decrypt++; + if (rs->rs_keyix == AR5K_RXKEYIX_INVALID && + !(rs->rs_status & AR5K_RXERR_CRC)) + return true; + } + if (rs->rs_status & AR5K_RXERR_MIC) { + sc->stats.rxerr_mic++; + return true; + } + + /* reject any frames with non-crypto errors */ + if (rs->rs_status & ~(AR5K_RXERR_DECRYPT)) + return false; + } + + if (unlikely(rs->rs_more)) { + sc->stats.rxerr_jumbo++; + return false; + } + return true; +} + +static void +ath5k_tasklet_rx(unsigned long data) +{ struct ath5k_rx_status rs = {}; struct sk_buff *skb, *next_skb; dma_addr_t next_skb_addr; @@ -1901,7 +1516,6 @@ ath5k_tasklet_rx(unsigned long data) struct ath5k_buf *bf; struct ath5k_desc *ds; int ret; - int rx_flag; spin_lock(&sc->rxbuflock); if (list_empty(&sc->rxbuf)) { @@ -1909,8 +1523,6 @@ ath5k_tasklet_rx(unsigned long data) goto unlock; } do { - rx_flag = 0; - bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); BUG_ON(bf->skb == NULL); skb = bf->skb; @@ -1926,150 +1538,153 @@ ath5k_tasklet_rx(unsigned long data) else if (unlikely(ret)) { ATH5K_ERR(sc, "error in processing rx descriptor\n"); sc->stats.rxerr_proc++; - spin_unlock(&sc->rxbuflock); - return; + break; } - sc->stats.rx_all_count++; - - if (unlikely(rs.rs_status)) { - if (rs.rs_status & AR5K_RXERR_CRC) - sc->stats.rxerr_crc++; - if (rs.rs_status & AR5K_RXERR_FIFO) - 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) { - /* - * Decrypt error. If the error occurred - * because there was no hardware key, then - * let the frame through so the upper layers - * can process it. This is necessary for 5210 - * parts which have no way to setup a ``clear'' - * key cache entry. - * - * XXX do key cache faulting - */ - sc->stats.rxerr_decrypt++; - if (rs.rs_keyix == AR5K_RXKEYIX_INVALID && - !(rs.rs_status & AR5K_RXERR_CRC)) - goto accept; - } - if (rs.rs_status & AR5K_RXERR_MIC) { - rx_flag |= RX_FLAG_MMIC_ERROR; - sc->stats.rxerr_mic++; - goto accept; - } + if (ath5k_receive_frame_ok(sc, &rs)) { + next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr); - /* let crypto-error packets fall through in MNTR */ - if ((rs.rs_status & - ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) || - sc->opmode != NL80211_IFTYPE_MONITOR) + /* + * If we can't replace bf->skb with a new skb under + * memory pressure, just skip this packet + */ + if (!next_skb) goto next; - } - if (unlikely(rs.rs_more)) { - sc->stats.rxerr_jumbo++; - goto next; + pci_unmap_single(sc->pdev, bf->skbaddr, + common->rx_bufsize, + PCI_DMA_FROMDEVICE); - } -accept: - next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr); + skb_put(skb, rs.rs_datalen); - /* - * If we can't replace bf->skb with a new skb under memory - * pressure, just skip this packet - */ - if (!next_skb) - goto next; + ath5k_receive_frame(sc, skb, &rs); - pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize, - PCI_DMA_FROMDEVICE); - skb_put(skb, rs.rs_datalen); + bf->skb = next_skb; + bf->skbaddr = next_skb_addr; + } +next: + list_move_tail(&bf->list, &sc->rxbuf); + } while (ath5k_rxbuf_setup(sc, bf) == 0); +unlock: + spin_unlock(&sc->rxbuflock); +} - /* The MAC header is padded to have 32-bit boundary if the - * packet payload is non-zero. The general calculation for - * padsize would take into account odd header lengths: - * padsize = (4 - hdrlen % 4) % 4; However, since only - * even-length headers are used, padding can only be 0 or 2 - * bytes and we can optimize this a bit. In addition, we must - * not try to remove padding from short control frames that do - * not have payload. */ - ath5k_remove_padding(skb); - rxs = IEEE80211_SKB_RXCB(skb); +/*************\ +* TX Handling * +\*************/ - /* - * always extend the mac timestamp, since this information is - * also needed for proper IBSS merging. - * - * XXX: it might be too late to do it here, since rs_tstamp is - * 15bit only. that means TSF extension has to be done within - * 32768usec (about 32ms). it might be necessary to move this to - * the interrupt handler, like it is done in madwifi. - * - * Unfortunately we don't know when the hardware takes the rx - * timestamp (beginning of phy frame, data frame, end of rx?). - * The only thing we know is that it is hardware specific... - * On AR5213 it seems the rx timestamp is at the end of the - * frame, but i'm not sure. - * - * NOTE: mac80211 defines mactime at the beginning of the first - * data symbol. Since we don't have any time references it's - * impossible to comply to that. This affects IBSS merge only - * right now, so it's not too bad... - */ - rxs->mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp); - rxs->flag = rx_flag | RX_FLAG_TSFT; +static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ath5k_txq *txq) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_buf *bf; + unsigned long flags; + int padsize; - rxs->freq = sc->curchan->center_freq; - rxs->band = sc->curband->band; + ath5k_debug_dump_skb(sc, skb, "TX ", 1); - rxs->signal = sc->ah->ah_noise_floor + rs.rs_rssi; + /* + * The hardware expects the header padded to 4 byte boundaries. + * If this is not the case, we add the padding after the header. + */ + padsize = ath5k_add_padding(skb); + if (padsize < 0) { + ATH5K_ERR(sc, "tx hdrlen not %%4: not enough" + " headroom to pad"); + goto drop_packet; + } - rxs->antenna = rs.rs_antenna; + if (txq->txq_len >= ATH5K_TXQ_LEN_MAX) + ieee80211_stop_queue(hw, txq->qnum); - if (rs.rs_antenna > 0 && rs.rs_antenna < 5) - sc->stats.antenna_rx[rs.rs_antenna]++; - else - sc->stats.antenna_rx[0]++; /* invalid */ + spin_lock_irqsave(&sc->txbuflock, flags); + if (list_empty(&sc->txbuf)) { + ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); + spin_unlock_irqrestore(&sc->txbuflock, flags); + ieee80211_stop_queues(hw); + goto drop_packet; + } + bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); + list_del(&bf->list); + sc->txbuf_len--; + if (list_empty(&sc->txbuf)) + ieee80211_stop_queues(hw); + spin_unlock_irqrestore(&sc->txbuflock, flags); - rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); - rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); + bf->skb = skb; - if (rxs->rate_idx >= 0 && rs.rs_rate == - sc->curband->bitrates[rxs->rate_idx].hw_value_short) - rxs->flag |= RX_FLAG_SHORTPRE; + if (ath5k_txbuf_setup(sc, bf, txq, padsize)) { + bf->skb = NULL; + spin_lock_irqsave(&sc->txbuflock, flags); + list_add_tail(&bf->list, &sc->txbuf); + sc->txbuf_len++; + spin_unlock_irqrestore(&sc->txbuflock, flags); + goto drop_packet; + } + return NETDEV_TX_OK; - ath5k_debug_dump_skb(sc, skb, "RX ", 0); +drop_packet: + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} - ath5k_update_beacon_rssi(sc, skb, rs.rs_rssi); +static void +ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, + struct ath5k_tx_status *ts) +{ + struct ieee80211_tx_info *info; + int i; - /* check beacons in IBSS mode */ - if (sc->opmode == NL80211_IFTYPE_ADHOC) - ath5k_check_ibss_tsf(sc, skb, rxs); + sc->stats.tx_all_count++; + sc->stats.tx_bytes_count += skb->len; + info = IEEE80211_SKB_CB(skb); - ieee80211_rx(sc->hw, skb); + ieee80211_tx_info_clear_status(info); + for (i = 0; i < 4; i++) { + struct ieee80211_tx_rate *r = + &info->status.rates[i]; - bf->skb = next_skb; - bf->skbaddr = next_skb_addr; -next: - list_move_tail(&bf->list, &sc->rxbuf); - } while (ath5k_rxbuf_setup(sc, bf) == 0); -unlock: - spin_unlock(&sc->rxbuflock); -} + if (ts->ts_rate[i]) { + r->idx = ath5k_hw_to_driver_rix(sc, ts->ts_rate[i]); + r->count = ts->ts_retry[i]; + } else { + r->idx = -1; + r->count = 0; + } + } + /* count the successful attempt as well */ + info->status.rates[ts->ts_final_idx].count++; + if (unlikely(ts->ts_status)) { + sc->stats.ack_fail++; + if (ts->ts_status & AR5K_TXERR_FILT) { + info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + sc->stats.txerr_filt++; + } + if (ts->ts_status & AR5K_TXERR_XRETRY) + sc->stats.txerr_retry++; + if (ts->ts_status & AR5K_TXERR_FIFO) + sc->stats.txerr_fifo++; + } else { + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.ack_signal = ts->ts_rssi; + } + /* + * Remove MAC header padding before giving the frame + * back to mac80211. + */ + ath5k_remove_padding(skb); -/*************\ -* TX Handling * -\*************/ + if (ts->ts_antenna > 0 && ts->ts_antenna < 5) + sc->stats.antenna_tx[ts->ts_antenna]++; + else + sc->stats.antenna_tx[0]++; /* invalid */ + + ieee80211_tx_status(sc->hw, skb); +} static void ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) @@ -2078,96 +1693,51 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) struct ath5k_buf *bf, *bf0; struct ath5k_desc *ds; struct sk_buff *skb; - struct ieee80211_tx_info *info; - int i, ret; + int ret; spin_lock(&txq->lock); 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; + txq->txq_poll_mark = false; - ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); - if (unlikely(ret == -EINPROGRESS)) - break; - else if (unlikely(ret)) { - ATH5K_ERR(sc, "error %d while processing queue %u\n", - ret, txq->qnum); - break; - } - - sc->stats.tx_all_count++; - skb = bf->skb; - info = IEEE80211_SKB_CB(skb); - bf->skb = NULL; + /* skb might already have been processed last time. */ + if (bf->skb != NULL) { + ds = bf->desc; - pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, - PCI_DMA_TODEVICE); - - ieee80211_tx_info_clear_status(info); - for (i = 0; i < 4; i++) { - struct ieee80211_tx_rate *r = - &info->status.rates[i]; - - if (ts.ts_rate[i]) { - r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]); - r->count = ts.ts_retry[i]; - } else { - r->idx = -1; - r->count = 0; + ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); + if (unlikely(ret == -EINPROGRESS)) + break; + else if (unlikely(ret)) { + ATH5K_ERR(sc, + "error %d while processing " + "queue %u\n", ret, txq->qnum); + break; } - } - - /* count the successful attempt as well */ - info->status.rates[ts.ts_final_idx].count++; - if (unlikely(ts.ts_status)) { - sc->stats.ack_fail++; - if (ts.ts_status & AR5K_TXERR_FILT) { - info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - sc->stats.txerr_filt++; - } - if (ts.ts_status & AR5K_TXERR_XRETRY) - sc->stats.txerr_retry++; - if (ts.ts_status & AR5K_TXERR_FIFO) - sc->stats.txerr_fifo++; - } else { - info->flags |= IEEE80211_TX_STAT_ACK; - info->status.ack_signal = ts.ts_rssi; + skb = bf->skb; + bf->skb = NULL; + pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, + PCI_DMA_TODEVICE); + ath5k_tx_frame_completed(sc, skb, &ts); } /* - * Remove MAC header padding before giving the frame - * back to mac80211. + * 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. + * Always keep the last descriptor to avoid HW races... */ - ath5k_remove_padding(skb); - - if (ts.ts_antenna > 0 && ts.ts_antenna < 5) - sc->stats.antenna_tx[ts.ts_antenna]++; - else - sc->stats.antenna_tx[0]++; /* invalid */ - - ieee80211_tx_status(sc->hw, skb); - - spin_lock(&sc->txbuflock); - list_move_tail(&bf->list, &sc->txbuf); - sc->txbuf_len++; - spin_unlock(&sc->txbuflock); + if (ath5k_hw_get_txdp(sc->ah, txq->qnum) != bf->daddr) { + spin_lock(&sc->txbuflock); + list_move_tail(&bf->list, &sc->txbuf); + sc->txbuf_len++; + txq->txq_len--; + spin_unlock(&sc->txbuflock); + } } - if (likely(list_empty(&txq->q))) - txq->link = NULL; spin_unlock(&txq->lock); - if (sc->txbuf_len > ATH_TXBUF / 5) - ieee80211_wake_queues(sc->hw); + if (txq->txq_len < ATH5K_TXQ_LEN_LOW && txq->qnum < 4) + ieee80211_wake_queue(sc->hw, txq->qnum); } static void @@ -2233,10 +1803,11 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) * default antenna which is supposed to be an omni. * * Note2: On sectored scenarios it's possible to have - * multiple antennas (1omni -the default- and 14 sectors) - * so if we choose to actually support this mode we need - * to allow user to set how many antennas we have and tweak - * the code below to send beacons on all of them. + * multiple antennas (1 omni -- the default -- and 14 + * sectors), so if we choose to actually support this + * mode, we need to allow the user to set how many antennas + * we have and tweak the code below to send beacons + * on all of them. */ if (ah->ah_ant_mode == AR5K_ANTMODE_SECTOR_AP) antenna = sc->bsent & 4 ? 2 : 1; @@ -2262,30 +1833,65 @@ err_unmap: } /* + * Updates the beacon that is sent by ath5k_beacon_send. For adhoc, + * this is called only once at config_bss time, for AP we do it every + * SWBA interrupt so that the TIM will reflect buffered frames. + * + * Called with the beacon lock. + */ +static int +ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + int ret; + struct ath5k_softc *sc = hw->priv; + struct ath5k_vif *avf = (void *)vif->drv_priv; + struct sk_buff *skb; + + if (WARN_ON(!vif)) { + ret = -EINVAL; + goto out; + } + + skb = ieee80211_beacon_get(hw, vif); + + if (!skb) { + ret = -ENOMEM; + goto out; + } + + ath5k_debug_dump_skb(sc, skb, "BC ", 1); + + ath5k_txbuf_free_skb(sc, avf->bbuf); + avf->bbuf->skb = skb; + ret = ath5k_beacon_setup(sc, avf->bbuf); + if (ret) + avf->bbuf->skb = NULL; +out: + return ret; +} + +/* * Transmit a beacon frame at SWBA. Dynamic updates to the * frame contents are done as needed and the slot time is * also adjusted based on current state. * - * This is called from software irq context (beacontq or restq - * tasklets) or user context from ath5k_beacon_config. + * This is called from software irq context (beacontq tasklets) + * or user context from ath5k_beacon_config. */ static void ath5k_beacon_send(struct ath5k_softc *sc) { - struct ath5k_buf *bf = sc->bbuf; struct ath5k_hw *ah = sc->ah; + struct ieee80211_vif *vif; + struct ath5k_vif *avf; + struct ath5k_buf *bf; struct sk_buff *skb; ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n"); - if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION || - sc->opmode == NL80211_IFTYPE_MONITOR)) { - ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL); - return; - } /* * Check if the previous beacon has gone out. If - * not don't don't try to post another, skip this + * not, don't don't try to post another: skip this * period and wait for the next. Missed beacons * indicate a problem and should not occur. If we * miss too many consecutive beacons reset the device. @@ -2298,7 +1904,9 @@ ath5k_beacon_send(struct ath5k_softc *sc) ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "stuck beacon time (%u missed)\n", sc->bmisscount); - tasklet_schedule(&sc->restq); + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, + "stuck beacon, resetting\n"); + ieee80211_queue_work(sc->hw, &sc->reset_work); } return; } @@ -2309,6 +1917,28 @@ ath5k_beacon_send(struct ath5k_softc *sc) sc->bmisscount = 0; } + if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) { + u64 tsf = ath5k_hw_get_tsf64(ah); + u32 tsftu = TSF_TO_TU(tsf); + int slot = ((tsftu % sc->bintval) * ATH_BCBUF) / sc->bintval; + vif = sc->bslot[(slot + 1) % ATH_BCBUF]; + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, + "tsf %llx tsftu %x intval %u slot %u vif %p\n", + (unsigned long long)tsf, tsftu, sc->bintval, slot, vif); + } else /* only one interface */ + vif = sc->bslot[0]; + + if (!vif) + return; + + avf = (void *)vif->drv_priv; + bf = avf->bbuf; + if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION || + sc->opmode == NL80211_IFTYPE_MONITOR)) { + ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL); + return; + } + /* * Stop any current dma and put the new frame on the queue. * This should never fail since we check above that no frames @@ -2321,23 +1951,22 @@ ath5k_beacon_send(struct ath5k_softc *sc) /* refresh the beacon for AP mode */ if (sc->opmode == NL80211_IFTYPE_AP) - ath5k_beacon_update(sc->hw, sc->vif); + ath5k_beacon_update(sc->hw, vif); ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); ath5k_hw_start_tx_dma(ah, sc->bhalq); ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", sc->bhalq, (unsigned long long)bf->daddr, bf->desc); - skb = ieee80211_get_buffered_bc(sc->hw, sc->vif); + skb = ieee80211_get_buffered_bc(sc->hw, vif); while (skb) { ath5k_tx_queue(sc->hw, skb, sc->cabq); - skb = ieee80211_get_buffered_bc(sc->hw, sc->vif); + skb = ieee80211_get_buffered_bc(sc->hw, vif); } sc->bsent++; } - /** * ath5k_beacon_update_timers - update beacon timers * @@ -2362,6 +1991,12 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) u64 hw_tsf; intval = sc->bintval & AR5K_BEACON_PERIOD; + if (sc->opmode == NL80211_IFTYPE_AP && sc->num_ap_vifs > 1) { + intval /= ATH_BCBUF; /* staggered multi-bss beacons */ + if (intval < 15) + ATH5K_WARN(sc, "intval %u is too low, min 15\n", + intval); + } if (WARN_ON(!intval)) return; @@ -2372,8 +2007,11 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) hw_tsf = ath5k_hw_get_tsf64(ah); hw_tu = TSF_TO_TU(hw_tsf); -#define FUDGE 3 - /* we use FUDGE to make sure the next TBTT is ahead of the current TU */ +#define FUDGE AR5K_TUNE_SW_BEACON_RESP + 3 + /* We use FUDGE to make sure the next TBTT is ahead of the current TU. + * Since we later substract AR5K_TUNE_SW_BEACON_RESP (10) in the timer + * configuration we need to make sure it is bigger than that. */ + if (bc_tsf == -1) { /* * no beacons received, called internally. @@ -2439,7 +2077,6 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) intval & AR5K_BEACON_RESET_TSF ? "AR5K_BEACON_RESET_TSF" : ""); } - /** * ath5k_beacon_config - Configure the beacon queues and interrupts * @@ -2518,152 +2155,6 @@ static void ath5k_tasklet_beacon(unsigned long data) * Interrupt handling * \********************/ -static int -ath5k_init(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - int ret, i; - - mutex_lock(&sc->lock); - - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode); - - /* - * Stop anything previously setup. This is safe - * no matter this is the first time through or not. - */ - ath5k_stop_locked(sc); - - /* - * The basic interface to setting the hardware in a good - * state is ``reset''. On return the hardware is known to - * be powered up and with interrupts disabled. This must - * be followed by initialization of the appropriate bits - * and then setup of the interrupt mask. - */ - sc->curchan = sc->hw->conf.channel; - 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_MIB; - - ret = ath5k_reset(sc, NULL); - if (ret) - goto done; - - ath5k_rfkill_hw_start(ah); - - /* - * Reset the key cache since some parts do not reset the - * contents on initial power up or resume from suspend. - */ - for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) - ath5k_hw_reset_key(ah, i); - - ath5k_hw_set_ack_bitrate_high(ah, true); - ret = 0; -done: - mmiowb(); - mutex_unlock(&sc->lock); - return ret; -} - -static int -ath5k_stop_locked(struct ath5k_softc *sc) -{ - struct ath5k_hw *ah = sc->ah; - - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "invalid %u\n", - test_bit(ATH_STAT_INVALID, sc->status)); - - /* - * Shutdown the hardware and driver: - * stop output from above - * disable interrupts - * turn off timers - * turn off the radio - * clear transmit machinery - * clear receive machinery - * drain and release tx queues - * reclaim beacon resources - * power down hardware - * - * Note that some of this work is not possible if the - * hardware is gone (invalid). - */ - ieee80211_stop_queues(sc->hw); - - if (!test_bit(ATH_STAT_INVALID, sc->status)) { - ath5k_led_off(sc); - ath5k_hw_set_imr(ah, 0); - synchronize_irq(sc->pdev->irq); - } - ath5k_txq_cleanup(sc); - if (!test_bit(ATH_STAT_INVALID, sc->status)) { - ath5k_rx_stop(sc); - ath5k_hw_phy_disable(ah); - } else - sc->rxlink = NULL; - - return 0; -} - -/* - * Stop the device, grabbing the top-level lock to protect - * against concurrent entry through ath5k_init (which can happen - * if another thread does a system call and the thread doing the - * stop is preempted). - */ -static int -ath5k_stop_hw(struct ath5k_softc *sc) -{ - int ret; - - mutex_lock(&sc->lock); - ret = ath5k_stop_locked(sc); - if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) { - /* - * Don't set the card in full sleep mode! - * - * a) When the device is in this state it must be carefully - * woken up or references to registers in the PCI clock - * domain may freeze the bus (and system). This varies - * by chip and is mostly an issue with newer parts - * (madwifi sources mentioned srev >= 0x78) that go to - * sleep more quickly. - * - * b) On older chips full sleep results a weird behaviour - * during wakeup. I tested various cards with srev < 0x78 - * and they don't wake up after module reload, a second - * module reload is needed to bring the card up again. - * - * Until we figure out what's going on don't enable - * full chip reset on any chip (this is what Legacy HAL - * and Sam's HAL do anyway). Instead Perform a full reset - * on the device (same as initial state after attach) and - * leave it idle (keep MAC/BB on warm reset) */ - ret = ath5k_hw_on_hold(sc->ah); - - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, - "putting device to sleep\n"); - } - ath5k_txbuf_free(sc, sc->bbuf); - - mmiowb(); - mutex_unlock(&sc->lock); - - tasklet_kill(&sc->rxtq); - tasklet_kill(&sc->txtq); - 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) { @@ -2705,7 +2196,9 @@ ath5k_intr(int irq, void *dev_id) * Fatal errors are unrecoverable. * Typically these are caused by DMA errors. */ - tasklet_schedule(&sc->restq); + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, + "fatal int, resetting\n"); + ieee80211_queue_work(sc->hw, &sc->reset_work); } else if (unlikely(status & AR5K_INT_RXORN)) { /* * Receive buffers are full. Either the bus is busy or @@ -2717,8 +2210,11 @@ ath5k_intr(int irq, void *dev_id) * this guess is copied from the HAL. */ sc->stats.rxorn_intr++; - if (ah->ah_mac_srev < AR5K_SREV_AR5212) - tasklet_schedule(&sc->restq); + if (ah->ah_mac_srev < AR5K_SREV_AR5212) { + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, + "rx overrun, resetting\n"); + ieee80211_queue_work(sc->hw, &sc->reset_work); + } else tasklet_schedule(&sc->rxtq); } else { @@ -2731,7 +2227,7 @@ ath5k_intr(int irq, void *dev_id) * RXE bit is written, but it doesn't work at * least on older hardware revs. */ - sc->rxlink = NULL; + sc->stats.rxeol_intr++; } if (status & AR5K_INT_TXURN) { /* bump tx trigger level */ @@ -2764,14 +2260,6 @@ ath5k_intr(int irq, void *dev_id) return IRQ_HANDLED; } -static void -ath5k_tasklet_reset(unsigned long data) -{ - struct ath5k_softc *sc = (void *)data; - - ath5k_reset(sc, sc->curchan); -} - /* * Periodically recalibrate the PHY to account * for temperature/environment changes. @@ -2785,10 +2273,6 @@ ath5k_tasklet_calibrate(unsigned long data) /* Only full calibration for now */ ah->ah_cal_mask |= AR5K_CALIBRATION_FULL; - /* Stop queues so that calibration - * doesn't interfere with tx */ - ieee80211_stop_queues(sc->hw); - ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", ieee80211_frequency_to_channel(sc->curchan->center_freq), sc->curchan->hw_value); @@ -2799,15 +2283,22 @@ ath5k_tasklet_calibrate(unsigned long data) * to load new gain values. */ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); - ath5k_reset(sc, sc->curchan); + ieee80211_queue_work(sc->hw, &sc->reset_work); } 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)); - /* Wake queues */ - ieee80211_wake_queues(sc->hw); + /* Noise floor calibration interrupts rx/tx path while I/Q calibration + * doesn't. + * TODO: We should stop TX here, so that it doesn't interfere. + * Note that stopping the queues is not enough to stop TX! */ + if (time_is_before_eq_jiffies(ah->ah_cal_next_nf)) { + ah->ah_cal_next_nf = jiffies + + msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_NF); + ath5k_hw_update_noise_floor(ah); + } ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; } @@ -2825,76 +2316,215 @@ ath5k_tasklet_ani(unsigned long data) } -/********************\ -* Mac80211 functions * -\********************/ +static void +ath5k_tx_complete_poll_work(struct work_struct *work) +{ + struct ath5k_softc *sc = container_of(work, struct ath5k_softc, + tx_complete_work.work); + struct ath5k_txq *txq; + int i; + bool needreset = false; + + for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) { + if (sc->txqs[i].setup) { + txq = &sc->txqs[i]; + spin_lock_bh(&txq->lock); + if (txq->txq_len > 1) { + if (txq->txq_poll_mark) { + ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, + "TX queue stuck %d\n", + txq->qnum); + needreset = true; + txq->txq_stuck++; + spin_unlock_bh(&txq->lock); + break; + } else { + txq->txq_poll_mark = true; + } + } + spin_unlock_bh(&txq->lock); + } + } + + if (needreset) { + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, + "TX queues stuck, resetting\n"); + ath5k_reset(sc, sc->curchan); + } + + ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, + msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT)); +} + + +/*************************\ +* Initialization routines * +\*************************/ static int -ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +ath5k_stop_locked(struct ath5k_softc *sc) { - struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "invalid %u\n", + test_bit(ATH_STAT_INVALID, sc->status)); - return ath5k_tx_queue(hw, skb, sc->txq); + /* + * Shutdown the hardware and driver: + * stop output from above + * disable interrupts + * turn off timers + * turn off the radio + * clear transmit machinery + * clear receive machinery + * drain and release tx queues + * reclaim beacon resources + * power down hardware + * + * Note that some of this work is not possible if the + * hardware is gone (invalid). + */ + ieee80211_stop_queues(sc->hw); + + if (!test_bit(ATH_STAT_INVALID, sc->status)) { + ath5k_led_off(sc); + ath5k_hw_set_imr(ah, 0); + synchronize_irq(sc->pdev->irq); + } + ath5k_txq_cleanup(sc); + if (!test_bit(ATH_STAT_INVALID, sc->status)) { + ath5k_rx_stop(sc); + ath5k_hw_phy_disable(ah); + } + + return 0; } -static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ath5k_txq *txq) +static int +ath5k_init(struct ath5k_softc *sc) { - struct ath5k_softc *sc = hw->priv; - struct ath5k_buf *bf; - unsigned long flags; - int padsize; + struct ath5k_hw *ah = sc->ah; + struct ath_common *common = ath5k_hw_common(ah); + int ret, i; - ath5k_debug_dump_skb(sc, skb, "TX ", 1); + mutex_lock(&sc->lock); - if (sc->opmode == NL80211_IFTYPE_MONITOR) - ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n"); + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode); /* - * the hardware expects the header padded to 4 byte boundaries - * if this is not the case we add the padding after the header + * Stop anything previously setup. This is safe + * no matter this is the first time through or not. */ - padsize = ath5k_add_padding(skb); - if (padsize < 0) { - ATH5K_ERR(sc, "tx hdrlen not %%4: not enough" - " headroom to pad"); - goto drop_packet; - } + ath5k_stop_locked(sc); - spin_lock_irqsave(&sc->txbuflock, flags); - if (list_empty(&sc->txbuf)) { - ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); - spin_unlock_irqrestore(&sc->txbuflock, flags); - ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); - goto drop_packet; - } - bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); - list_del(&bf->list); - sc->txbuf_len--; - if (list_empty(&sc->txbuf)) - ieee80211_stop_queues(hw); - spin_unlock_irqrestore(&sc->txbuflock, flags); + /* + * The basic interface to setting the hardware in a good + * state is ``reset''. On return the hardware is known to + * be powered up and with interrupts disabled. This must + * be followed by initialization of the appropriate bits + * and then setup of the interrupt mask. + */ + sc->curchan = sc->hw->conf.channel; + 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_MIB; - bf->skb = skb; + ret = ath5k_reset(sc, NULL); + if (ret) + goto done; - if (ath5k_txbuf_setup(sc, bf, txq, padsize)) { - bf->skb = NULL; - spin_lock_irqsave(&sc->txbuflock, flags); - list_add_tail(&bf->list, &sc->txbuf); - sc->txbuf_len++; - spin_unlock_irqrestore(&sc->txbuflock, flags); - goto drop_packet; + ath5k_rfkill_hw_start(ah); + + /* + * Reset the key cache since some parts do not reset the + * contents on initial power up or resume from suspend. + */ + for (i = 0; i < common->keymax; i++) + ath_hw_keyreset(common, (u16) i); + + ath5k_hw_set_ack_bitrate_high(ah, true); + + for (i = 0; i < ARRAY_SIZE(sc->bslot); i++) + sc->bslot[i] = NULL; + + ret = 0; +done: + mmiowb(); + mutex_unlock(&sc->lock); + + ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, + msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT)); + + return ret; +} + +static void stop_tasklets(struct ath5k_softc *sc) +{ + tasklet_kill(&sc->rxtq); + tasklet_kill(&sc->txtq); + tasklet_kill(&sc->calib); + tasklet_kill(&sc->beacontq); + tasklet_kill(&sc->ani_tasklet); +} + +/* + * Stop the device, grabbing the top-level lock to protect + * against concurrent entry through ath5k_init (which can happen + * if another thread does a system call and the thread doing the + * stop is preempted). + */ +static int +ath5k_stop_hw(struct ath5k_softc *sc) +{ + int ret; + + mutex_lock(&sc->lock); + ret = ath5k_stop_locked(sc); + if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) { + /* + * Don't set the card in full sleep mode! + * + * a) When the device is in this state it must be carefully + * woken up or references to registers in the PCI clock + * domain may freeze the bus (and system). This varies + * by chip and is mostly an issue with newer parts + * (madwifi sources mentioned srev >= 0x78) that go to + * sleep more quickly. + * + * b) On older chips full sleep results a weird behaviour + * during wakeup. I tested various cards with srev < 0x78 + * and they don't wake up after module reload, a second + * module reload is needed to bring the card up again. + * + * Until we figure out what's going on don't enable + * full chip reset on any chip (this is what Legacy HAL + * and Sam's HAL do anyway). Instead Perform a full reset + * on the device (same as initial state after attach) and + * leave it idle (keep MAC/BB on warm reset) */ + ret = ath5k_hw_on_hold(sc->ah); + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, + "putting device to sleep\n"); } - return NETDEV_TX_OK; -drop_packet: - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; + mmiowb(); + mutex_unlock(&sc->lock); + + stop_tasklets(sc); + + cancel_delayed_work_sync(&sc->tx_complete_work); + + ath5k_rfkill_hw_stop(sc->ah); + + return ret; } /* * Reset the hardware. If chan is not NULL, then also pause rx/tx * and change to the given channel. + * + * This should be called with sc->lock. */ static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan) @@ -2904,8 +2534,11 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan) ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n"); + ath5k_hw_set_imr(ah, 0); + synchronize_irq(sc->pdev->irq); + stop_tasklets(sc); + if (chan) { - ath5k_hw_set_imr(ah, 0); ath5k_txq_cleanup(sc); ath5k_rx_stop(sc); @@ -2926,6 +2559,10 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan) ath5k_ani_init(ah, ah->ah_sc->ani_state.ani_mode); + ah->ah_cal_next_full = jiffies; + ah->ah_cal_next_ani = jiffies; + ah->ah_cal_next_nf = jiffies; + /* * Change channels and update the h/w rate map if we're switching; * e.g. 11a to 11b/g. @@ -2947,6 +2584,218 @@ err: return ret; } +static void ath5k_reset_work(struct work_struct *work) +{ + struct ath5k_softc *sc = container_of(work, struct ath5k_softc, + reset_work); + + mutex_lock(&sc->lock); + ath5k_reset(sc, sc->curchan); + mutex_unlock(&sc->lock); +} + +static int +ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah); + struct ath5k_txq *txq; + u8 mac[ETH_ALEN] = {}; + int ret; + + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); + + /* + * Check if the MAC has multi-rate retry support. + * We do this by trying to setup a fake extended + * descriptor. MACs that don't have support will + * return false w/o doing anything. MACs that do + * support it will return true w/o doing anything. + */ + ret = ath5k_hw_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0); + + if (ret < 0) + goto err; + if (ret > 0) + __set_bit(ATH_STAT_MRRETRY, sc->status); + + /* + * Collect the channel list. The 802.11 layer + * is resposible for filtering this list based + * on settings like the phy mode and regulatory + * domain restrictions. + */ + ret = ath5k_setup_bands(hw); + if (ret) { + ATH5K_ERR(sc, "can't get channels\n"); + goto err; + } + + /* NB: setup here so ath5k_rate_update is happy */ + if (test_bit(AR5K_MODE_11A, ah->ah_modes)) + ath5k_setcurmode(sc, AR5K_MODE_11A); + else + ath5k_setcurmode(sc, AR5K_MODE_11B); + + /* + * Allocate tx+rx descriptors and populate the lists. + */ + ret = ath5k_desc_alloc(sc, pdev); + if (ret) { + ATH5K_ERR(sc, "can't allocate descriptors\n"); + goto err; + } + + /* + * Allocate hardware transmit queues: one queue for + * beacon frames and one data queue for each QoS + * priority. Note that hw functions handle resetting + * these queues at the needed time. + */ + ret = ath5k_beaconq_setup(ah); + if (ret < 0) { + ATH5K_ERR(sc, "can't setup a beacon xmit queue\n"); + goto err_desc; + } + sc->bhalq = ret; + sc->cabq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0); + if (IS_ERR(sc->cabq)) { + ATH5K_ERR(sc, "can't setup cab queue\n"); + ret = PTR_ERR(sc->cabq); + goto err_bhal; + } + + /* This order matches mac80211's queue priority, so we can + * directly use the mac80211 queue number without any mapping */ + txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VO); + if (IS_ERR(txq)) { + ATH5K_ERR(sc, "can't setup xmit queue\n"); + ret = PTR_ERR(txq); + goto err_queues; + } + txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_VI); + if (IS_ERR(txq)) { + ATH5K_ERR(sc, "can't setup xmit queue\n"); + ret = PTR_ERR(txq); + goto err_queues; + } + txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE); + if (IS_ERR(txq)) { + ATH5K_ERR(sc, "can't setup xmit queue\n"); + ret = PTR_ERR(txq); + goto err_queues; + } + txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK); + if (IS_ERR(txq)) { + ATH5K_ERR(sc, "can't setup xmit queue\n"); + ret = PTR_ERR(txq); + goto err_queues; + } + hw->queues = 4; + + tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); + tasklet_init(&sc->txtq, ath5k_tasklet_tx, (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); + + INIT_WORK(&sc->reset_work, ath5k_reset_work); + INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work); + + ret = ath5k_eeprom_read_mac(ah, mac); + if (ret) { + ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", + sc->pdev->device); + goto err_queues; + } + + SET_IEEE80211_PERM_ADDR(hw, mac); + memcpy(&sc->lladdr, mac, ETH_ALEN); + /* All MAC address bits matter for ACKs */ + ath5k_update_bssid_mask_and_opmode(sc, NULL); + + regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; + ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier); + if (ret) { + ATH5K_ERR(sc, "can't initialize regulatory system\n"); + goto err_queues; + } + + ret = ieee80211_register_hw(hw); + if (ret) { + ATH5K_ERR(sc, "can't register ieee80211 hw\n"); + goto err_queues; + } + + if (!ath_is_world_regd(regulatory)) + regulatory_hint(hw->wiphy, regulatory->alpha2); + + ath5k_init_leds(sc); + + ath5k_sysfs_register(sc); + + return 0; +err_queues: + ath5k_txq_release(sc); +err_bhal: + ath5k_hw_release_tx_queue(ah, sc->bhalq); +err_desc: + ath5k_desc_free(sc, pdev); +err: + return ret; +} + +static void +ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + + /* + * NB: the order of these is important: + * o call the 802.11 layer before detaching ath5k_hw to + * ensure callbacks into the driver to delete global + * key cache entries can be handled + * o reclaim the tx queue data structures after calling + * the 802.11 layer as we'll get called back to reclaim + * node state and potentially want to use them + * o to cleanup the tx queues the hal is called, so detach + * it last + * XXX: ??? detach ath5k_hw ??? + * Other than that, it's straightforward... + */ + ieee80211_unregister_hw(hw); + ath5k_desc_free(sc, pdev); + ath5k_txq_release(sc); + ath5k_hw_release_tx_queue(sc->ah, sc->bhalq); + ath5k_unregister_leds(sc); + + ath5k_sysfs_unregister(sc); + /* + * NB: can't reclaim these until after ieee80211_ifdetach + * returns because we'll get called back to reclaim node + * state and potentially want to use them. + */ +} + +/********************\ +* Mac80211 functions * +\********************/ + +static int +ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ath5k_softc *sc = hw->priv; + u16 qnum = skb_get_queue_mapping(skb); + + if (WARN_ON(qnum >= sc->ah->ah_capabilities.cap_queues.q_tx_num)) { + dev_kfree_skb_any(skb); + return 0; + } + + return ath5k_tx_queue(hw, skb, &sc->txqs[qnum]); +} + static int ath5k_start(struct ieee80211_hw *hw) { return ath5k_init(hw->priv); @@ -2962,32 +2811,78 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, { struct ath5k_softc *sc = hw->priv; int ret; + struct ath5k_vif *avf = (void *)vif->drv_priv; mutex_lock(&sc->lock); - if (sc->vif) { - ret = 0; + + if ((vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_ADHOC) + && (sc->num_ap_vifs + sc->num_adhoc_vifs) >= ATH_BCBUF) { + ret = -ELNRNG; goto end; } - sc->vif = vif; + /* Don't allow other interfaces if one ad-hoc is configured. + * TODO: Fix the problems with ad-hoc and multiple other interfaces. + * We would need to operate the HW in ad-hoc mode to allow TSF updates + * for the IBSS, but this breaks with additional AP or STA interfaces + * at the moment. */ + if (sc->num_adhoc_vifs || + (sc->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) { + ATH5K_ERR(sc, "Only one single ad-hoc interface is allowed.\n"); + ret = -ELNRNG; + goto end; + } switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_MONITOR: - sc->opmode = vif->type; + avf->opmode = vif->type; break; default: ret = -EOPNOTSUPP; goto end; } - ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", sc->opmode); + sc->nvifs++; + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode); + + /* Assign the vap/adhoc to a beacon xmit slot. */ + if ((avf->opmode == NL80211_IFTYPE_AP) || + (avf->opmode == NL80211_IFTYPE_ADHOC)) { + int slot; + + WARN_ON(list_empty(&sc->bcbuf)); + avf->bbuf = list_first_entry(&sc->bcbuf, struct ath5k_buf, + list); + list_del(&avf->bbuf->list); + + avf->bslot = 0; + for (slot = 0; slot < ATH_BCBUF; slot++) { + if (!sc->bslot[slot]) { + avf->bslot = slot; + break; + } + } + BUG_ON(sc->bslot[avf->bslot] != NULL); + sc->bslot[avf->bslot] = vif; + if (avf->opmode == NL80211_IFTYPE_AP) + sc->num_ap_vifs++; + else + sc->num_adhoc_vifs++; + } + /* Any MAC address is fine, all others are included through the + * filter. + */ + memcpy(&sc->lladdr, vif->addr, ETH_ALEN); ath5k_hw_set_lladdr(sc->ah, vif->addr); - ath5k_mode_setup(sc); + + memcpy(&avf->lladdr, vif->addr, ETH_ALEN); + + ath5k_mode_setup(sc, vif); ret = 0; end: @@ -3000,15 +2895,29 @@ ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath5k_softc *sc = hw->priv; - u8 mac[ETH_ALEN] = {}; + struct ath5k_vif *avf = (void *)vif->drv_priv; + unsigned int i; mutex_lock(&sc->lock); - if (sc->vif != vif) - goto end; + sc->nvifs--; + + if (avf->bbuf) { + ath5k_txbuf_free_skb(sc, avf->bbuf); + list_add_tail(&avf->bbuf->list, &sc->bcbuf); + for (i = 0; i < ATH_BCBUF; i++) { + if (sc->bslot[i] == vif) { + sc->bslot[i] = NULL; + break; + } + } + avf->bbuf = NULL; + } + if (avf->opmode == NL80211_IFTYPE_AP) + sc->num_ap_vifs--; + else if (avf->opmode == NL80211_IFTYPE_ADHOC) + sc->num_adhoc_vifs--; - ath5k_hw_set_lladdr(sc->ah, mac); - sc->vif = NULL; -end: + ath5k_update_bssid_mask_and_opmode(sc, NULL); mutex_unlock(&sc->lock); } @@ -3091,6 +3000,19 @@ static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, return ((u64)(mfilt[1]) << 32) | mfilt[0]; } +static bool ath_any_vif_assoc(struct ath5k_softc *sc) +{ + struct ath_vif_iter_data iter_data; + iter_data.hw_macaddr = NULL; + iter_data.any_assoc = false; + iter_data.need_set_hw_addr = false; + iter_data.found_active = true; + + ieee80211_iterate_active_interfaces_atomic(sc->hw, ath_vif_iter, + &iter_data); + return iter_data.any_assoc; +} + #define SUPPORTED_FIF_FLAGS \ FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ @@ -3160,9 +3082,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, rfilt |= AR5K_RX_FILTER_PHYERR; /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons - * and probes for any BSSID, this needs testing */ - if (*new_flags & FIF_BCN_PRBRESP_PROMISC) - rfilt |= AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ; + * and probes for any BSSID */ + if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (sc->nvifs > 1)) + rfilt |= AR5K_RX_FILTER_BEACON; /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not * set we should only pass on control frames for this @@ -3178,7 +3100,6 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, switch (sc->opmode) { case NL80211_IFTYPE_MESH_POINT: - case NL80211_IFTYPE_MONITOR: rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ | @@ -3201,7 +3122,7 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, /* Set multicast bits */ ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]); - /* Set the cached hw filter flags, this will alter actually + /* Set the cached hw filter flags, this will later actually * be set in HW */ sc->filter_flags = rfilt; @@ -3221,17 +3142,14 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (modparam_nohwcrypt) return -EOPNOTSUPP; - if (sc->opmode == NL80211_IFTYPE_AP) - return -EOPNOTSUPP; - - switch (key->alg) { - case ALG_WEP: - case ALG_TKIP: + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: break; - case ALG_CCMP: - if (sc->ah->ah_aes_support) + case WLAN_CIPHER_SUITE_CCMP: + if (common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM) break; - return -EOPNOTSUPP; default: WARN_ON(1); @@ -3242,27 +3160,25 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch (cmd) { case SET_KEY: - ret = ath5k_hw_set_key(sc->ah, key->keyidx, key, - sta ? sta->addr : NULL); - if (ret) { - ATH5K_ERR(sc, "can't set the key\n"); - goto unlock; + ret = ath_key_config(common, vif, sta, key); + if (ret >= 0) { + key->hw_key_idx = ret; + /* push IV and Michael MIC generation to stack */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + if (key->cipher == WLAN_CIPHER_SUITE_TKIP) + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + if (key->cipher == WLAN_CIPHER_SUITE_CCMP) + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; + ret = 0; } - __set_bit(key->keyidx, common->keymap); - key->hw_key_idx = key->keyidx; - key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV | - IEEE80211_KEY_FLAG_GENERATE_MMIC); break; case DISABLE_KEY: - ath5k_hw_reset_key(sc->ah, key->keyidx); - __clear_bit(key->keyidx, common->keymap); + ath_key_delete(common, key); break; default: ret = -EINVAL; - goto unlock; } -unlock: mmiowb(); mutex_unlock(&sc->lock); return ret; @@ -3332,43 +3248,6 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) ath5k_hw_reset_tsf(sc->ah); } -/* - * Updates the beacon that is sent by ath5k_beacon_send. For adhoc, - * this is called only once at config_bss time, for AP we do it every - * SWBA interrupt so that the TIM will reflect buffered frames. - * - * Called with the beacon lock. - */ -static int -ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - int ret; - struct ath5k_softc *sc = hw->priv; - struct sk_buff *skb; - - if (WARN_ON(!vif)) { - ret = -EINVAL; - goto out; - } - - skb = ieee80211_beacon_get(hw, vif); - - if (!skb) { - ret = -ENOMEM; - goto out; - } - - ath5k_debug_dump_skb(sc, skb, "BC ", 1); - - ath5k_txbuf_free(sc, sc->bbuf); - sc->bbuf->skb = skb; - ret = ath5k_beacon_setup(sc, sc->bbuf); - if (ret) - sc->bbuf->skb = NULL; -out: - return ret; -} - static void set_beacon_filter(struct ieee80211_hw *hw, bool enable) { @@ -3389,20 +3268,19 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changes) { + struct ath5k_vif *avf = (void *)vif->drv_priv; struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; struct ath_common *common = ath5k_hw_common(ah); unsigned long flags; mutex_lock(&sc->lock); - if (WARN_ON(sc->vif != vif)) - goto unlock; if (changes & BSS_CHANGED_BSSID) { /* Cache for later use during resets */ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); common->curaid = 0; - ath5k_hw_set_associd(ah); + ath5k_hw_set_bssid(ah); mmiowb(); } @@ -3410,7 +3288,12 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, sc->bintval = bss_conf->beacon_int; if (changes & BSS_CHANGED_ASSOC) { - sc->assoc = bss_conf->assoc; + avf->assoc = bss_conf->assoc; + if (bss_conf->assoc) + sc->assoc = bss_conf->assoc; + else + sc->assoc = ath_any_vif_assoc(sc); + if (sc->opmode == NL80211_IFTYPE_STATION) set_beacon_filter(hw, sc->assoc); ath5k_hw_set_ledstate(sc->ah, sc->assoc ? @@ -3420,7 +3303,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, "Bss Info ASSOC %d, bssid: %pM\n", bss_conf->aid, common->curbssid); common->curaid = bss_conf->aid; - ath5k_hw_set_associd(ah); + ath5k_hw_set_bssid(ah); /* Once ANI is available you would start it here */ } } @@ -3438,7 +3321,6 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, BSS_CHANGED_BEACON_INT)) ath5k_beacon_config(sc); - unlock: mutex_unlock(&sc->lock); } @@ -3474,3 +3356,400 @@ static void ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) ath5k_hw_set_coverage_class(sc->ah, coverage_class); mutex_unlock(&sc->lock); } + +static int ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + struct ath5k_txq_info qi; + int ret = 0; + + if (queue >= ah->ah_capabilities.cap_queues.q_tx_num) + return 0; + + mutex_lock(&sc->lock); + + ath5k_hw_get_tx_queueprops(ah, queue, &qi); + + qi.tqi_aifs = params->aifs; + qi.tqi_cw_min = params->cw_min; + qi.tqi_cw_max = params->cw_max; + qi.tqi_burst_time = params->txop; + + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, + "Configure tx [queue %d], " + "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", + queue, params->aifs, params->cw_min, + params->cw_max, params->txop); + + if (ath5k_hw_set_tx_queueprops(ah, queue, &qi)) { + ATH5K_ERR(sc, + "Unable to update hardware queue %u!\n", queue); + ret = -EIO; + } else + ath5k_hw_reset_tx_queue(ah, queue); + + mutex_unlock(&sc->lock); + + return ret; +} + +static const struct ieee80211_ops ath5k_hw_ops = { + .tx = ath5k_tx, + .start = ath5k_start, + .stop = ath5k_stop, + .add_interface = ath5k_add_interface, + .remove_interface = ath5k_remove_interface, + .config = ath5k_config, + .prepare_multicast = ath5k_prepare_multicast, + .configure_filter = ath5k_configure_filter, + .set_key = ath5k_set_key, + .get_stats = ath5k_get_stats, + .get_survey = ath5k_get_survey, + .conf_tx = ath5k_conf_tx, + .get_tsf = ath5k_get_tsf, + .set_tsf = ath5k_set_tsf, + .reset_tsf = ath5k_reset_tsf, + .bss_info_changed = ath5k_bss_info_changed, + .sw_scan_start = ath5k_sw_scan_start, + .sw_scan_complete = ath5k_sw_scan_complete, + .set_coverage_class = ath5k_set_coverage_class, +}; + +/********************\ +* PCI Initialization * +\********************/ + +static int __devinit +ath5k_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + void __iomem *mem; + struct ath5k_softc *sc; + struct ath_common *common; + struct ieee80211_hw *hw; + int ret; + u8 csz; + + /* + * L0s needs to be disabled on all ath5k cards. + * + * For distributions shipping with CONFIG_PCIEASPM (this will be enabled + * by default in the future in 2.6.36) this will also mean both L1 and + * L0s will be disabled when a pre 1.1 PCIe device is detected. We do + * know L1 works correctly even for all ath5k pre 1.1 PCIe devices + * though but cannot currently undue the effect of a blacklist, for + * details you can read pcie_aspm_sanity_check() and see how it adjusts + * the device link capability. + * + * It may be possible in the future to implement some PCI API to allow + * drivers to override blacklists for pre 1.1 PCIe but for now it is + * best to accept that both L0s and L1 will be disabled completely for + * distributions shipping with CONFIG_PCIEASPM rather than having this + * issue present. Motivation for adding this new API will be to help + * with power consumption for some of these devices. + */ + pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S); + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "can't enable device\n"); + goto err; + } + + /* XXX 32-bit addressing only */ + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "32-bit DMA not available\n"); + goto err_dis; + } + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); + if (csz == 0) { + /* + * Linux 2.4.18 (at least) writes the cache line size + * register as a 16-bit wide register which is wrong. + * We must have this setup properly for rx buffer + * DMA to work so force a reasonable value here if it + * comes up zero. + */ + csz = L1_CACHE_BYTES >> 2; + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); + } + /* + * The default setting of latency timer yields poor results, + * set it to the value used by other systems. It may be worth + * tweaking this setting more. + */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); + + /* Enable bus mastering */ + pci_set_master(pdev); + + /* + * Disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state. + */ + pci_write_config_byte(pdev, 0x41, 0); + + ret = pci_request_region(pdev, 0, "ath5k"); + if (ret) { + dev_err(&pdev->dev, "cannot reserve PCI memory region\n"); + goto err_dis; + } + + mem = pci_iomap(pdev, 0, 0); + if (!mem) { + dev_err(&pdev->dev, "cannot remap PCI memory region\n") ; + ret = -EIO; + goto err_reg; + } + + /* + * Allocate hw (mac80211 main struct) + * and hw->priv (driver private data) + */ + hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops); + if (hw == NULL) { + dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n"); + ret = -ENOMEM; + goto err_map; + } + + dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy)); + + /* Initialize driver private data */ + SET_IEEE80211_DEV(hw, &pdev->dev); + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT); + + hw->extra_tx_headroom = 2; + hw->channel_change_time = 5000; + sc = hw->priv; + sc->hw = hw; + sc->pdev = pdev; + + /* + * Mark the device as detached to avoid processing + * interrupts until setup is complete. + */ + __set_bit(ATH_STAT_INVALID, sc->status); + + sc->iobase = mem; /* So we can unmap it on detach */ + sc->opmode = NL80211_IFTYPE_STATION; + sc->bintval = 1000; + mutex_init(&sc->lock); + spin_lock_init(&sc->rxbuflock); + spin_lock_init(&sc->txbuflock); + spin_lock_init(&sc->block); + + /* Set private data */ + pci_set_drvdata(pdev, sc); + + /* Setup interrupt handler */ + ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); + if (ret) { + ATH5K_ERR(sc, "request_irq failed\n"); + goto err_free; + } + + /* If we passed the test, malloc an ath5k_hw struct */ + sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL); + if (!sc->ah) { + ret = -ENOMEM; + ATH5K_ERR(sc, "out of memory\n"); + goto err_irq; + } + + sc->ah->ah_sc = sc; + sc->ah->ah_iobase = sc->iobase; + common = ath5k_hw_common(sc->ah); + common->ops = &ath5k_common_ops; + common->ah = sc->ah; + common->hw = hw; + common->cachelsz = csz << 2; /* convert to bytes */ + spin_lock_init(&common->cc_lock); + + /* Initialize device */ + ret = ath5k_hw_attach(sc); + if (ret) { + goto err_free_ah; + } + + /* set up multi-rate retry capabilities */ + if (sc->ah->ah_version == AR5K_AR5212) { + hw->max_rates = 4; + hw->max_rate_tries = 11; + } + + hw->vif_data_size = sizeof(struct ath5k_vif); + + /* Finish private driver data initialization */ + ret = ath5k_attach(pdev, hw); + if (ret) + goto err_ah; + + ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n", + ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev), + sc->ah->ah_mac_srev, + sc->ah->ah_phy_revision); + + if (!sc->ah->ah_single_chip) { + /* Single chip radio (!RF5111) */ + if (sc->ah->ah_radio_5ghz_revision && + !sc->ah->ah_radio_2ghz_revision) { + /* No 5GHz support -> report 2GHz radio */ + if (!test_bit(AR5K_MODE_11A, + sc->ah->ah_capabilities.cap_mode)) { + ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + /* No 2GHz support (5110 and some + * 5Ghz only cards) -> report 5Ghz radio */ + } else if (!test_bit(AR5K_MODE_11B, + sc->ah->ah_capabilities.cap_mode)) { + ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + /* Multiband radio */ + } else { + ATH5K_INFO(sc, "RF%s multiband radio found" + " (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + } + } + /* Multi chip radio (RF5111 - RF2111) -> + * report both 2GHz/5GHz radios */ + else if (sc->ah->ah_radio_5ghz_revision && + sc->ah->ah_radio_2ghz_revision){ + ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD, + sc->ah->ah_radio_2ghz_revision), + sc->ah->ah_radio_2ghz_revision); + } + } + + ath5k_debug_init_device(sc); + + /* ready to process interrupts */ + __clear_bit(ATH_STAT_INVALID, sc->status); + + return 0; +err_ah: + ath5k_hw_detach(sc->ah); +err_free_ah: + kfree(sc->ah); +err_irq: + free_irq(pdev->irq, sc); +err_free: + ieee80211_free_hw(hw); +err_map: + pci_iounmap(pdev, mem); +err_reg: + pci_release_region(pdev, 0); +err_dis: + pci_disable_device(pdev); +err: + return ret; +} + +static void __devexit +ath5k_pci_remove(struct pci_dev *pdev) +{ + struct ath5k_softc *sc = pci_get_drvdata(pdev); + + ath5k_debug_finish_device(sc); + ath5k_detach(pdev, sc->hw); + ath5k_hw_detach(sc->ah); + kfree(sc->ah); + free_irq(pdev->irq, sc); + pci_iounmap(pdev, sc->iobase); + pci_release_region(pdev, 0); + pci_disable_device(pdev); + ieee80211_free_hw(sc->hw); +} + +#ifdef CONFIG_PM_SLEEP +static int ath5k_pci_suspend(struct device *dev) +{ + struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev)); + + ath5k_led_off(sc); + return 0; +} + +static int ath5k_pci_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct ath5k_softc *sc = pci_get_drvdata(pdev); + + /* + * Suspend/Resume resets the PCI configuration space, so we have to + * re-disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state + */ + pci_write_config_byte(pdev, 0x41, 0); + + ath5k_led_enable(sc); + return 0; +} + +static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume); +#define ATH5K_PM_OPS (&ath5k_pm_ops) +#else +#define ATH5K_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +static struct pci_driver ath5k_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = ath5k_pci_id_table, + .probe = ath5k_pci_probe, + .remove = __devexit_p(ath5k_pci_remove), + .driver.pm = ATH5K_PM_OPS, +}; + +/* + * Module init/exit functions + */ +static int __init +init_ath5k_pci(void) +{ + int ret; + + ret = pci_register_driver(&ath5k_pci_driver); + if (ret) { + printk(KERN_ERR "ath5k_pci: can't register pci driver\n"); + return ret; + } + + return 0; +} + +static void __exit +exit_ath5k_pci(void) +{ + pci_unregister_driver(&ath5k_pci_driver); +} + +module_init(init_ath5k_pci); +module_exit(exit_ath5k_pci); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 56221bc7c8cd..9a79773cdc2a 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -47,6 +47,7 @@ #include <linux/if_ether.h> #include <linux/leds.h> #include <linux/rfkill.h> +#include <linux/workqueue.h> #include "ath5k.h" #include "debug.h" @@ -57,7 +58,9 @@ #define ATH_RXBUF 40 /* number of RX buffers */ #define ATH_TXBUF 200 /* number of TX buffers */ -#define ATH_BCBUF 1 /* number of beacon buffers */ +#define ATH_BCBUF 4 /* number of beacon buffers */ +#define ATH5K_TXQ_LEN_MAX (ATH_TXBUF / 4) /* bufs per queue */ +#define ATH5K_TXQ_LEN_LOW (ATH5K_TXQ_LEN_MAX / 2) /* low mark */ struct ath5k_buf { struct list_head list; @@ -82,6 +85,9 @@ struct ath5k_txq { struct list_head q; /* transmit queue */ spinlock_t lock; /* lock on q and link */ bool setup; + int txq_len; /* number of queued buffers */ + bool txq_poll_mark; + unsigned int txq_stuck; /* informational counter */ }; #define ATH5K_LED_MAX_NAME_LEN 31 @@ -115,6 +121,13 @@ struct ath5k_statistics { /* frame errors */ unsigned int rx_all_count; /* all RX frames, including errors */ unsigned int tx_all_count; /* all TX frames, including errors */ + unsigned int rx_bytes_count; /* all RX bytes, including errored pks + * and the MAC headers for each packet + */ + unsigned int tx_bytes_count; /* all TX bytes, including errored pkts + * and the MAC headers and padding for + * each packet. + */ unsigned int rxerr_crc; unsigned int rxerr_phy; unsigned int rxerr_phy_code[32]; @@ -136,6 +149,7 @@ struct ath5k_statistics { unsigned int mib_intr; unsigned int rxorn_intr; + unsigned int rxeol_intr; }; #if CHAN_DEBUG @@ -144,6 +158,14 @@ struct ath5k_statistics { #define ATH_CHAN_MAX (14+14+14+252+20) #endif +struct ath5k_vif { + bool assoc; /* are we associated or not */ + enum nl80211_iftype opmode; + int bslot; + struct ath5k_buf *bbuf; /* beacon buffer */ + u8 lladdr[ETH_ALEN]; +}; + /* Software Carrier, keeps track of the driver state * associated with an instance of a device */ struct ath5k_softc { @@ -180,16 +202,17 @@ struct ath5k_softc { unsigned int curmode; /* current phy mode */ struct ieee80211_channel *curchan; /* current h/w channel */ - struct ieee80211_vif *vif; + u16 nvifs; enum ath5k_int imask; /* interrupt mask copy */ + u8 lladdr[ETH_ALEN]; u8 bssidmask[ETH_ALEN]; unsigned int led_pin, /* GPIO pin for driving LED */ led_on; /* pin setting for LED on */ - struct tasklet_struct restq; /* reset tasklet */ + struct work_struct reset_work; /* deferred chip reset */ unsigned int rxbufsize; /* rx size based on mtu */ struct list_head rxbuf; /* receive buffer */ @@ -202,7 +225,6 @@ struct ath5k_softc { spinlock_t txbuflock; unsigned int txbuf_len; /* buf count in txbuf list */ struct ath5k_txq txqs[AR5K_NUM_TX_QUEUES]; /* tx queues */ - struct ath5k_txq *txq; /* main tx queue */ struct tasklet_struct txtq; /* tx intr tasklet */ struct ath5k_led tx_led; /* tx led */ @@ -212,7 +234,10 @@ struct ath5k_softc { spinlock_t block; /* protects beacon */ struct tasklet_struct beacontq; /* beacon intr tasklet */ - struct ath5k_buf *bbuf; /* beacon buffer */ + struct list_head bcbuf; /* beacon buffer */ + struct ieee80211_vif *bslot[ATH_BCBUF]; + u16 num_ap_vifs; + u16 num_adhoc_vifs; unsigned int bhalq, /* SW q for outgoing beacons */ bmisscount, /* missed beacon transmits */ bintval, /* beacon interval in TU */ @@ -228,6 +253,8 @@ struct ath5k_softc { struct ath5k_ani_state ani_state; struct tasklet_struct ani_tasklet; /* ANI calibration */ + + struct delayed_work tx_complete_work; }; #define ath5k_hw_hasbssidmask(_ah) \ diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c index 74f007126f41..beae519aa735 100644 --- a/drivers/net/wireless/ath/ath5k/caps.c +++ b/drivers/net/wireless/ath/ath5k/caps.c @@ -34,7 +34,6 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) { u16 ee_header; - ATH5K_TRACE(ah->ah_sc); /* Capabilities stored in the EEPROM */ ee_header = ah->ah_capabilities.cap_eeprom.ee_header; @@ -123,8 +122,6 @@ int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result) { - ATH5K_TRACE(ah->ah_sc); - switch (cap_type) { case AR5K_CAP_NUM_TXQUEUES: if (result) { @@ -173,8 +170,6 @@ yes: int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id) { - ATH5K_TRACE(ah->ah_sc); - if (ah->ah_version == AR5K_AR5210) { AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); @@ -186,8 +181,6 @@ int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, int ath5k_hw_disable_pspoll(struct ath5k_hw *ah) { - ATH5K_TRACE(ah->ah_sc); - if (ah->ah_version == AR5K_AR5210) { AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 6fb5c5ffa5b1..acda56ee521b 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -60,6 +60,7 @@ #include "base.h" #include "debug.h" +#include "../debug.h" static unsigned int ath5k_debug; module_param_named(debug, ath5k_debug, uint, 0); @@ -71,8 +72,6 @@ module_param_named(debug, ath5k_debug, uint, 0); #include "reg.h" #include "ani.h" -static struct dentry *ath5k_global_debugfs; - static int ath5k_debugfs_open(struct inode *inode, struct file *file) { file->private_data = inode->i_private; @@ -239,6 +238,9 @@ static ssize_t read_file_beacon(struct file *file, char __user *user_buf, "TSF\t\t0x%016llx\tTU: %08x\n", (unsigned long long)tsf, TSF_TO_TU(tsf)); + if (len > sizeof(buf)) + len = sizeof(buf); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -268,6 +270,7 @@ static const struct file_operations fops_beacon = { .write = write_file_beacon, .open = ath5k_debugfs_open, .owner = THIS_MODULE, + .llseek = default_llseek, }; @@ -278,7 +281,8 @@ static ssize_t write_file_reset(struct file *file, size_t count, loff_t *ppos) { struct ath5k_softc *sc = file->private_data; - tasklet_schedule(&sc->restq); + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "debug file triggered reset\n"); + ieee80211_queue_work(sc->hw, &sc->reset_work); return count; } @@ -286,6 +290,7 @@ static const struct file_operations fops_reset = { .write = write_file_reset, .open = ath5k_debugfs_open, .owner = THIS_MODULE, + .llseek = noop_llseek, }; @@ -307,8 +312,8 @@ static const struct { { ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" }, { 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_DESC, "desc", "descriptor chains" }, { ATH5K_DEBUG_ANY, "all", "show all debug levels" }, }; @@ -334,6 +339,9 @@ static ssize_t read_file_debug(struct file *file, char __user *user_buf, sc->debug.level == dbg_info[i].level ? '+' : ' ', dbg_info[i].level, dbg_info[i].desc); + if (len > sizeof(buf)) + len = sizeof(buf); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -363,6 +371,7 @@ static const struct file_operations fops_debug = { .write = write_file_debug, .open = ath5k_debugfs_open, .owner = THIS_MODULE, + .llseek = default_llseek, }; @@ -426,6 +435,16 @@ static ssize_t read_file_antenna(struct file *file, char __user *user_buf, "AR5K_PHY_FAST_ANT_DIV_EN\t%d\n", (v & AR5K_PHY_FAST_ANT_DIV_EN) != 0); + v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_ANT_SWITCH_TABLE_0); + len += snprintf(buf+len, sizeof(buf)-len, + "\nAR5K_PHY_ANT_SWITCH_TABLE_0\t0x%08x\n", v); + v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_ANT_SWITCH_TABLE_1); + len += snprintf(buf+len, sizeof(buf)-len, + "AR5K_PHY_ANT_SWITCH_TABLE_1\t0x%08x\n", v); + + if (len > sizeof(buf)) + len = sizeof(buf); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -464,6 +483,61 @@ static const struct file_operations fops_antenna = { .write = write_file_antenna, .open = ath5k_debugfs_open, .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +/* debugfs: misc */ + +static ssize_t read_file_misc(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + char buf[700]; + unsigned int len = 0; + u32 filt = ath5k_hw_get_rx_filter(sc->ah); + + len += snprintf(buf+len, sizeof(buf)-len, "bssid-mask: %pM\n", + sc->bssidmask); + len += snprintf(buf+len, sizeof(buf)-len, "filter-flags: 0x%x ", + filt); + if (filt & AR5K_RX_FILTER_UCAST) + len += snprintf(buf+len, sizeof(buf)-len, " UCAST"); + if (filt & AR5K_RX_FILTER_MCAST) + len += snprintf(buf+len, sizeof(buf)-len, " MCAST"); + if (filt & AR5K_RX_FILTER_BCAST) + len += snprintf(buf+len, sizeof(buf)-len, " BCAST"); + if (filt & AR5K_RX_FILTER_CONTROL) + len += snprintf(buf+len, sizeof(buf)-len, " CONTROL"); + if (filt & AR5K_RX_FILTER_BEACON) + len += snprintf(buf+len, sizeof(buf)-len, " BEACON"); + if (filt & AR5K_RX_FILTER_PROM) + len += snprintf(buf+len, sizeof(buf)-len, " PROM"); + if (filt & AR5K_RX_FILTER_XRPOLL) + len += snprintf(buf+len, sizeof(buf)-len, " XRPOLL"); + if (filt & AR5K_RX_FILTER_PROBEREQ) + len += snprintf(buf+len, sizeof(buf)-len, " PROBEREQ"); + if (filt & AR5K_RX_FILTER_PHYERR_5212) + len += snprintf(buf+len, sizeof(buf)-len, " PHYERR-5212"); + if (filt & AR5K_RX_FILTER_RADARERR_5212) + len += snprintf(buf+len, sizeof(buf)-len, " RADARERR-5212"); + if (filt & AR5K_RX_FILTER_PHYERR_5211) + snprintf(buf+len, sizeof(buf)-len, " PHYERR-5211"); + if (filt & AR5K_RX_FILTER_RADARERR_5211) + len += snprintf(buf+len, sizeof(buf)-len, " RADARERR-5211"); + + len += snprintf(buf+len, sizeof(buf)-len, "\nopmode: %s (%d)\n", + ath_opmode_to_string(sc->opmode), sc->opmode); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_misc = { + .read = read_file_misc, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE, }; @@ -517,6 +591,8 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf, st->rxerr_jumbo*100/st->rx_all_count : 0); len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%d]\n", st->rx_all_count); + len += snprintf(buf+len, sizeof(buf)-len, "RX-all-bytes\t%d\n", + st->rx_bytes_count); len += snprintf(buf+len, sizeof(buf)-len, "\nTX\n---------------------\n"); @@ -534,6 +610,11 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf, st->txerr_filt*100/st->tx_all_count : 0); len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%d]\n", st->tx_all_count); + len += snprintf(buf+len, sizeof(buf)-len, "TX-all-bytes\t%d\n", + st->tx_bytes_count); + + if (len > sizeof(buf)) + len = sizeof(buf); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -572,6 +653,7 @@ static const struct file_operations fops_frameerrors = { .write = write_file_frameerrors, .open = ath5k_debugfs_open, .owner = THIS_MODULE, + .llseek = default_llseek, }; @@ -638,20 +720,21 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, len += snprintf(buf+len, sizeof(buf)-len, "beacon RSSI average:\t%d\n", sc->ah->ah_beacon_rssi_avg.avg); + +#define CC_PRINT(_struct, _field) \ + _struct._field, \ + _struct.cycles > 0 ? \ + _struct._field*100/_struct.cycles : 0 + 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); + CC_PRINT(as->last_cc, tx_frame)); 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); + CC_PRINT(as->last_cc, rx_frame)); 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); + CC_PRINT(as->last_cc, rx_busy)); +#undef CC_PRINT len += snprintf(buf+len, sizeof(buf)-len, "profcnt cycles\t\t%u\n", - as->pfc_cycles); + as->last_cc.cycles); len += snprintf(buf+len, sizeof(buf)-len, "listen time\t\t%d\tlast: %d\n", as->listen_time, as->last_listen); @@ -674,6 +757,9 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2))); + if (len > sizeof(buf)) + len = sizeof(buf); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -726,24 +812,88 @@ static const struct file_operations fops_ani = { .write = write_file_ani, .open = ath5k_debugfs_open, .owner = THIS_MODULE, + .llseek = default_llseek, }; -/* init */ +/* debugfs: queues etc */ -void -ath5k_debug_init(void) +static ssize_t read_file_queue(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + char buf[700]; + unsigned int len = 0; + + struct ath5k_txq *txq; + struct ath5k_buf *bf, *bf0; + int i, n; + + len += snprintf(buf+len, sizeof(buf)-len, + "available txbuffers: %d\n", sc->txbuf_len); + + for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) { + txq = &sc->txqs[i]; + + len += snprintf(buf+len, sizeof(buf)-len, + "%02d: %ssetup\n", i, txq->setup ? "" : "not "); + + if (!txq->setup) + continue; + + n = 0; + spin_lock_bh(&txq->lock); + list_for_each_entry_safe(bf, bf0, &txq->q, list) + n++; + spin_unlock_bh(&txq->lock); + + len += snprintf(buf+len, sizeof(buf)-len, + " len: %d bufs: %d\n", txq->txq_len, n); + len += snprintf(buf+len, sizeof(buf)-len, + " stuck: %d\n", txq->txq_stuck); + } + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_queue(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) { - ath5k_global_debugfs = debugfs_create_dir("ath5k", NULL); + 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, "start", 5) == 0) + ieee80211_wake_queues(sc->hw); + else if (strncmp(buf, "stop", 4) == 0) + ieee80211_stop_queues(sc->hw); + + return count; } + +static const struct file_operations fops_queue = { + .read = read_file_queue, + .write = write_file_queue, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + + void ath5k_debug_init_device(struct ath5k_softc *sc) { sc->debug.level = ath5k_debug; - sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy), - ath5k_global_debugfs); + sc->debug.debugfs_phydir = debugfs_create_dir("ath5k", + sc->hw->wiphy->debugfsdir); sc->debug.debugfs_debug = debugfs_create_file("debug", S_IWUSR | S_IRUSR, @@ -763,6 +913,10 @@ ath5k_debug_init_device(struct ath5k_softc *sc) S_IWUSR | S_IRUSR, sc->debug.debugfs_phydir, sc, &fops_antenna); + sc->debug.debugfs_misc = debugfs_create_file("misc", + S_IRUSR, + sc->debug.debugfs_phydir, sc, &fops_misc); + sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, sc->debug.debugfs_phydir, sc, @@ -772,12 +926,11 @@ ath5k_debug_init_device(struct ath5k_softc *sc) S_IWUSR | S_IRUSR, sc->debug.debugfs_phydir, sc, &fops_ani); -} -void -ath5k_debug_finish(void) -{ - debugfs_remove(ath5k_global_debugfs); + sc->debug.debugfs_queue = debugfs_create_file("queue", + S_IWUSR | S_IRUSR, + sc->debug.debugfs_phydir, sc, + &fops_queue); } void @@ -788,8 +941,10 @@ ath5k_debug_finish_device(struct ath5k_softc *sc) debugfs_remove(sc->debug.debugfs_beacon); debugfs_remove(sc->debug.debugfs_reset); debugfs_remove(sc->debug.debugfs_antenna); + debugfs_remove(sc->debug.debugfs_misc); debugfs_remove(sc->debug.debugfs_frameerrors); debugfs_remove(sc->debug.debugfs_ani); + debugfs_remove(sc->debug.debugfs_queue); debugfs_remove(sc->debug.debugfs_phydir); } @@ -852,7 +1007,7 @@ ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done, ds, (unsigned long long)bf->daddr, ds->ds_link, ds->ds_data, rd->rx_ctl.rx_control_0, rd->rx_ctl.rx_control_1, - rd->u.rx_stat.rx_status_0, rd->u.rx_stat.rx_status_0, + rd->rx_stat.rx_status_0, rd->rx_stat.rx_status_1, !done ? ' ' : (rs->rs_status == 0) ? '*' : '!'); } @@ -864,10 +1019,10 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) struct ath5k_rx_status rs = {}; int status; - if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) + if (likely(!(sc->debug.level & ATH5K_DEBUG_DESC))) return; - printk(KERN_DEBUG "rx queue %x, link %p\n", + printk(KERN_DEBUG "rxdp %x, rxlink %p\n", ath5k_hw_get_rxdp(ah), sc->rxlink); spin_lock_bh(&sc->rxbuflock); @@ -906,7 +1061,7 @@ ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf) struct ath5k_tx_status ts = {}; int done; - if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) + if (likely(!(sc->debug.level & ATH5K_DEBUG_DESC))) return; done = sc->ah->ah_proc_tx_desc(sc->ah, bf->desc, &ts); diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h index ddd5b3a99e8d..236edbd2507d 100644 --- a/drivers/net/wireless/ath/ath5k/debug.h +++ b/drivers/net/wireless/ath/ath5k/debug.h @@ -75,8 +75,10 @@ struct ath5k_dbg_info { struct dentry *debugfs_beacon; struct dentry *debugfs_reset; struct dentry *debugfs_antenna; + struct dentry *debugfs_misc; struct dentry *debugfs_frameerrors; struct dentry *debugfs_ani; + struct dentry *debugfs_queue; }; /** @@ -94,6 +96,7 @@ struct ath5k_dbg_info { * @ATH5K_DEBUG_DUMP_TX: print transmit skb content * @ATH5K_DEBUG_DUMPBANDS: dump bands * @ATH5K_DEBUG_TRACE: trace function calls + * @ATH5K_DEBUG_DESC: descriptor setup * @ATH5K_DEBUG_ANY: show at any debug level * * The debug level is used to control the amount and type of debugging output @@ -115,18 +118,13 @@ enum ath5k_debug_level { ATH5K_DEBUG_DUMP_RX = 0x00000100, ATH5K_DEBUG_DUMP_TX = 0x00000200, ATH5K_DEBUG_DUMPBANDS = 0x00000400, - ATH5K_DEBUG_TRACE = 0x00001000, ATH5K_DEBUG_ANI = 0x00002000, + ATH5K_DEBUG_DESC = 0x00004000, ATH5K_DEBUG_ANY = 0xffffffff }; #ifdef CONFIG_ATH5K_DEBUG -#define ATH5K_TRACE(_sc) do { \ - if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \ - printk(KERN_DEBUG "ath5k trace %s:%d\n", __func__, __LINE__); \ - } while (0) - #define ATH5K_DBG(_sc, _m, _fmt, ...) do { \ if (unlikely((_sc)->debug.level & (_m) && net_ratelimit())) \ ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \ @@ -140,15 +138,9 @@ enum ath5k_debug_level { } while (0) void -ath5k_debug_init(void); - -void ath5k_debug_init_device(struct ath5k_softc *sc); void -ath5k_debug_finish(void); - -void ath5k_debug_finish_device(struct ath5k_softc *sc); void @@ -168,8 +160,6 @@ ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf); #include <linux/compiler.h> -#define ATH5K_TRACE(_sc) typecheck(struct ath5k_softc *, (_sc)) - static inline void __attribute__ ((format (printf, 3, 4))) ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {} @@ -178,15 +168,9 @@ ATH5K_DBG_UNLIMIT(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {} static inline void -ath5k_debug_init(void) {} - -static inline void ath5k_debug_init_device(struct ath5k_softc *sc) {} static inline void -ath5k_debug_finish(void) {} - -static inline void ath5k_debug_finish_device(struct ath5k_softc *sc) {} static inline void diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 7d7b646ab65a..43244382f213 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -91,14 +91,13 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; /* - * Verify and set header length - * XXX: I only found that on 5210 code, does it work on 5211 ? + * Verify and set header length (only 5210) */ if (ah->ah_version == AR5K_AR5210) { - if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN) + if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210) return -EINVAL; tx_ctl->tx_control_0 |= - AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN); + AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210); } /*Differences between 5210-5211*/ @@ -110,11 +109,11 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, case AR5K_PKT_TYPE_PIFS: frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS; default: - frame_type = type /*<< 2 ?*/; + frame_type = type; } tx_ctl->tx_control_0 |= - AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) | + AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210) | AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); } else { @@ -123,21 +122,30 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); tx_ctl->tx_control_1 |= - AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE); + AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211); } + #define _TX_FLAGS(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) { \ tx_ctl->tx_control_##_c |= \ AR5K_2W_TX_DESC_CTL##_c##_##_flag; \ } - +#define _TX_FLAGS_5211(_c, _flag) \ + if (flags & AR5K_TXDESC_##_flag) { \ + tx_ctl->tx_control_##_c |= \ + AR5K_2W_TX_DESC_CTL##_c##_##_flag##_5211; \ + } _TX_FLAGS(0, CLRDMASK); - _TX_FLAGS(0, VEOL); _TX_FLAGS(0, INTREQ); _TX_FLAGS(0, RTSENA); - _TX_FLAGS(1, NOACK); + + if (ah->ah_version == AR5K_AR5211) { + _TX_FLAGS_5211(0, VEOL); + _TX_FLAGS_5211(1, NOACK); + } #undef _TX_FLAGS +#undef _TX_FLAGS_5211 /* * WEP crap @@ -147,7 +155,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, - AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); + AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX); } /* @@ -156,7 +164,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, if ((ah->ah_version == AR5K_AR5210) && (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) tx_ctl->tx_control_1 |= rtscts_duration & - AR5K_2W_TX_DESC_CTL1_RTS_DURATION; + AR5K_2W_TX_DESC_CTL1_RTS_DURATION_5210; return 0; } @@ -176,7 +184,6 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, struct ath5k_hw_4w_tx_ctl *tx_ctl; unsigned int frame_len; - ATH5K_TRACE(ah->ah_sc); tx_ctl = &desc->ud.ds_tx5212.tx_ctl; /* @@ -256,7 +263,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if (key_index != AR5K_TXKEYIX_INVALID) { tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, - AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); + AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX); } /* @@ -278,13 +285,17 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, /* * Initialize a 4-word multi rate retry tx control descriptor on 5212 */ -static int +int ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) { struct ath5k_hw_4w_tx_ctl *tx_ctl; + /* no mrr support for cards older than 5212 */ + if (ah->ah_version < AR5K_AR5212) + return 0; + /* * Rates can be 0 as long as the retry count is 0 too. * A zero rate and nonzero retry count will put the HW into a mode where @@ -324,15 +335,6 @@ ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, return 0; } -/* no mrr support for cards older than 5212 */ -static int -ath5k_hw_setup_no_mrr(struct ath5k_hw *ah, struct ath5k_desc *desc, - unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, - u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) -{ - return 0; -} - /* * Proccess the tx status descriptor on 5210/5211 */ @@ -342,8 +344,6 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, struct ath5k_hw_2w_tx_ctl *tx_ctl; struct ath5k_hw_tx_status *tx_status; - ATH5K_TRACE(ah->ah_sc); - tx_ctl = &desc->ud.ds_tx5210.tx_ctl; tx_status = &desc->ud.ds_tx5210.tx_stat; @@ -396,8 +396,6 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_tx_status *tx_status; - ATH5K_TRACE(ah->ah_sc); - tx_ctl = &desc->ud.ds_tx5212.tx_ctl; tx_status = &desc->ud.ds_tx5212.tx_stat; @@ -419,11 +417,11 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); ts->ts_antenna = (tx_status->tx_status_1 & - AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; + AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1; ts->ts_status = 0; ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1, - AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX); + AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212); /* The longretry counter has the number of un-acked retries * for the final rate. To get the total number of retries @@ -485,12 +483,11 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, /* * Initialize an rx control descriptor */ -static int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, - u32 size, unsigned int flags) +int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + u32 size, unsigned int flags) { struct ath5k_hw_rx_ctl *rx_ctl; - ATH5K_TRACE(ah->ah_sc); rx_ctl = &desc->ud.ds_rx.rx_ctl; /* @@ -502,10 +499,11 @@ static int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, */ memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc)); + if (unlikely(size & ~AR5K_DESC_RX_CTL1_BUF_LEN)) + return -EINVAL; + /* Setup descriptor */ rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; - if (unlikely(rx_ctl->rx_control_1 != size)) - return -EINVAL; if (flags & AR5K_RXDESC_INTREQ) rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; @@ -521,13 +519,15 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, { struct ath5k_hw_rx_status *rx_status; - rx_status = &desc->ud.ds_rx.u.rx_stat; + rx_status = &desc->ud.ds_rx.rx_stat; /* No frame received / not ready */ if (unlikely(!(rx_status->rx_status_1 & - AR5K_5210_RX_DESC_STATUS1_DONE))) + AR5K_5210_RX_DESC_STATUS1_DONE))) return -EINPROGRESS; + memset(rs, 0, sizeof(struct ath5k_rx_status)); + /* * Frame receive status */ @@ -537,15 +537,23 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL); rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE); - rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0, - AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA); rs->rs_more = !!(rx_status->rx_status_0 & AR5K_5210_RX_DESC_STATUS0_MORE); - /* TODO: this timestamp is 13 bit, later on we assume 15 bit */ + /* TODO: this timestamp is 13 bit, later on we assume 15 bit! + * also the HAL code for 5210 says the timestamp is bits [10..22] of the + * TSF, and extends the timestamp here to 15 bit. + * we need to check on 5210... + */ rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); - rs->rs_status = 0; - rs->rs_phyerr = 0; + + if (ah->ah_version == AR5K_AR5211) + rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5211); + else + rs->rs_antenna = (rx_status->rx_status_0 & + AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5210) + ? 2 : 1; /* * Key table status @@ -560,19 +568,21 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, * Receive/descriptor errors */ if (!(rx_status->rx_status_1 & - AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { + AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_CRC_ERROR) rs->rs_status |= AR5K_RXERR_CRC; - if (rx_status->rx_status_1 & - AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN) + /* only on 5210 */ + if ((ah->ah_version == AR5K_AR5210) && + (rx_status->rx_status_1 & + AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN_5210)) rs->rs_status |= AR5K_RXERR_FIFO; if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) { rs->rs_status |= AR5K_RXERR_PHY; - rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1, + rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, AR5K_5210_RX_DESC_STATUS1_PHY_ERROR); } @@ -588,22 +598,20 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, * Proccess the rx status descriptor on 5212 */ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, - struct ath5k_desc *desc, struct ath5k_rx_status *rs) + struct ath5k_desc *desc, + struct ath5k_rx_status *rs) { struct ath5k_hw_rx_status *rx_status; - struct ath5k_hw_rx_error *rx_err; - ATH5K_TRACE(ah->ah_sc); - rx_status = &desc->ud.ds_rx.u.rx_stat; - - /* Overlay on error */ - rx_err = &desc->ud.ds_rx.u.rx_err; + rx_status = &desc->ud.ds_rx.rx_stat; /* No frame received / not ready */ if (unlikely(!(rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_DONE))) + AR5K_5212_RX_DESC_STATUS1_DONE))) return -EINPROGRESS; + memset(rs, 0, sizeof(struct ath5k_rx_status)); + /* * Frame receive status */ @@ -619,15 +627,13 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, AR5K_5212_RX_DESC_STATUS0_MORE); rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); - rs->rs_status = 0; - rs->rs_phyerr = 0; /* * Key table status */ if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, - AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); + AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); else rs->rs_keyix = AR5K_RXKEYIX_INVALID; @@ -635,7 +641,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, * Receive/descriptor errors */ if (!(rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { + AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) rs->rs_status |= AR5K_RXERR_CRC; @@ -643,9 +649,10 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { 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); + rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE); + if (!ah->ah_capabilities.cap_has_phyerr_counters) + ath5k_ani_phy_error_report(ah, rs->rs_phyerr); } if (rx_status->rx_status_1 & @@ -656,7 +663,6 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) rs->rs_status |= AR5K_RXERR_MIC; } - return 0; } @@ -665,29 +671,15 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, */ int ath5k_hw_init_desc_functions(struct ath5k_hw *ah) { - - if (ah->ah_version != AR5K_AR5210 && - ah->ah_version != AR5K_AR5211 && - ah->ah_version != AR5K_AR5212) - return -ENOTSUPP; - if (ah->ah_version == AR5K_AR5212) { - ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc; ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc; - ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc; ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status; - } else { - ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc; + ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status; + } else if (ah->ah_version <= AR5K_AR5211) { ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc; - ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_no_mrr; ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status; - } - - if (ah->ah_version == AR5K_AR5212) - ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status; - else if (ah->ah_version <= AR5K_AR5211) ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status; - + } else + return -ENOTSUPP; return 0; } - diff --git a/drivers/net/wireless/ath/ath5k/desc.h b/drivers/net/wireless/ath/ath5k/desc.h index 64538fbe4167..b2adb2a281c2 100644 --- a/drivers/net/wireless/ath/ath5k/desc.h +++ b/drivers/net/wireless/ath/ath5k/desc.h @@ -17,28 +17,24 @@ */ /* - * Internal RX/TX descriptor structures - * (rX: reserved fields possibily used by future versions of the ar5k chipset) + * RX/TX descriptor structures */ /* - * common hardware RX control descriptor + * Common hardware RX control descriptor */ struct ath5k_hw_rx_ctl { u32 rx_control_0; /* RX control word 0 */ u32 rx_control_1; /* RX control word 1 */ } __packed; -/* RX control word 0 field/sflags */ -#define AR5K_DESC_RX_CTL0 0x00000000 - /* RX control word 1 fields/flags */ -#define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff -#define AR5K_DESC_RX_CTL1_INTREQ 0x00002000 +#define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff /* data buffer length */ +#define AR5K_DESC_RX_CTL1_INTREQ 0x00002000 /* RX interrupt request */ /* - * common hardware RX status descriptor - * 5210/11 and 5212 differ only in the flags defined below + * Common hardware RX status descriptor + * 5210, 5211 and 5212 differ only in the fields and flags defined below */ struct ath5k_hw_rx_status { u32 rx_status_0; /* RX status word 0 */ @@ -47,81 +43,69 @@ struct ath5k_hw_rx_status { /* 5210/5211 */ /* RX status word 0 fields/flags */ -#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN 0x00000fff -#define AR5K_5210_RX_DESC_STATUS0_MORE 0x00001000 -#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000 +#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN 0x00000fff /* RX data length */ +#define AR5K_5210_RX_DESC_STATUS0_MORE 0x00001000 /* more desc for this frame */ +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5210 0x00004000 /* [5210] receive on ant 1 */ +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000 /* reception rate */ #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S 15 -#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000 /* rssi */ #define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19 -#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000 -#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27 +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5211 0x38000000 /* [5211] receive antenna */ +#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANT_5211_S 27 /* RX status word 1 fields/flags */ -#define AR5K_5210_RX_DESC_STATUS1_DONE 0x00000001 -#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 -#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR 0x00000004 -#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008 -#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010 -#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR 0x000000e0 +#define AR5K_5210_RX_DESC_STATUS1_DONE 0x00000001 /* descriptor complete */ +#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 /* reception success */ +#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR 0x00000004 /* CRC error */ +#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN_5210 0x00000008 /* [5210] FIFO overrun */ +#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010 /* decyption CRC failure */ +#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR 0x000000e0 /* PHY error */ #define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S 5 -#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 -#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX 0x00007e00 +#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 /* key index valid */ +#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX 0x00007e00 /* decyption key index */ #define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S 9 -#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000 +#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000 /* 13 bit of TSF */ #define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15 -#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000 +#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000 /* key cache miss */ /* 5212 */ /* RX status word 0 fields/flags */ -#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN 0x00000fff -#define AR5K_5212_RX_DESC_STATUS0_MORE 0x00001000 -#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000 -#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000 +#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN 0x00000fff /* RX data length */ +#define AR5K_5212_RX_DESC_STATUS0_MORE 0x00001000 /* more desc for this frame */ +#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000 /* decompression CRC error */ +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000 /* reception rate */ #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S 15 -#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000 /* rssi */ #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20 -#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000 +#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000 /* receive antenna */ #define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28 /* RX status word 1 fields/flags */ -#define AR5K_5212_RX_DESC_STATUS1_DONE 0x00000001 -#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 -#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR 0x00000004 -#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008 -#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR 0x00000010 -#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR 0x00000020 -#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 -#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00 +#define AR5K_5212_RX_DESC_STATUS1_DONE 0x00000001 /* descriptor complete */ +#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 /* frame reception success */ +#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR 0x00000004 /* CRC error */ +#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008 /* decryption CRC failure */ +#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR 0x00000010 /* PHY error */ +#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR 0x00000020 /* MIC decrypt error */ +#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 /* key index valid */ +#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00 /* decryption key index */ #define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S 9 -#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000 +#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000 /* first 15bit of the TSF */ #define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16 -#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000 - -/* - * common hardware RX error descriptor - */ -struct ath5k_hw_rx_error { - u32 rx_error_0; /* RX status word 0 */ - u32 rx_error_1; /* RX status word 1 */ -} __packed; - -/* RX error word 0 fields/flags */ -#define AR5K_RX_DESC_ERROR0 0x00000000 - -/* RX error word 1 fields/flags */ -#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE 0x0000ff00 -#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S 8 +#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000 /* key cache miss */ +#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE 0x0000ff00 /* phy error code overlays key index and valid fields */ +#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE_S 8 /** * 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_UNDERRUN = 0, /* Transmit underrun, [5210] No error */ 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_RADAR = 5, /* Radar detect, [5210] 64 QAM rate */ AR5K_RX_PHY_ERROR_SERVICE = 6, /* Illegal service */ AR5K_RX_PHY_ERROR_TOR = 7, /* Transmit override receive */ /* these are specific to the 5212 */ @@ -148,112 +132,111 @@ struct ath5k_hw_2w_tx_ctl { } __packed; /* TX control word 0 fields/flags */ -#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff -#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN 0x0003f000 /*[5210 ?]*/ -#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S 12 -#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE 0x003c0000 +#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff /* frame length */ +#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210 0x0003f000 /* [5210] header length */ +#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210_S 12 +#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE 0x003c0000 /* tx rate */ #define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S 18 -#define AR5K_2W_TX_DESC_CTL0_RTSENA 0x00400000 -#define AR5K_2W_TX_DESC_CTL0_CLRDMASK 0x01000000 -#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET 0x00800000 /*[5210]*/ -#define AR5K_2W_TX_DESC_CTL0_VEOL 0x00800000 /*[5211]*/ -#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE 0x1c000000 /*[5210]*/ -#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S 26 -#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 0x02000000 -#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211 0x1e000000 - +#define AR5K_2W_TX_DESC_CTL0_RTSENA 0x00400000 /* RTS/CTS enable */ +#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET_5210 0x00800000 /* [5210] long packet */ +#define AR5K_2W_TX_DESC_CTL0_VEOL_5211 0x00800000 /* [5211] virtual end-of-list */ +#define AR5K_2W_TX_DESC_CTL0_CLRDMASK 0x01000000 /* clear destination mask */ +#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 0x02000000 /* [5210] antenna selection */ +#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211 0x1e000000 /* [5211] antenna selection */ #define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT \ (ah->ah_version == AR5K_AR5210 ? \ AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \ AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211) - #define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25 -#define AR5K_2W_TX_DESC_CTL0_INTREQ 0x20000000 -#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 +#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210 0x1c000000 /* [5210] frame type */ +#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210_S 26 +#define AR5K_2W_TX_DESC_CTL0_INTREQ 0x20000000 /* TX interrupt request */ +#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 /* key is valid */ /* TX control word 1 fields/flags */ -#define AR5K_2W_TX_DESC_CTL1_BUF_LEN 0x00000fff -#define AR5K_2W_TX_DESC_CTL1_MORE 0x00001000 -#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 0x0007e000 -#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211 0x000fe000 - -#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX \ +#define AR5K_2W_TX_DESC_CTL1_BUF_LEN 0x00000fff /* data buffer length */ +#define AR5K_2W_TX_DESC_CTL1_MORE 0x00001000 /* more desc for this frame */ +#define AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_5210 0x0007e000 /* [5210] key table index */ +#define AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_5211 0x000fe000 /* [5211] key table index */ +#define AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX \ (ah->ah_version == AR5K_AR5210 ? \ - AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \ - AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211) - -#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13 -#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE 0x00700000 /*[5211]*/ -#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S 20 -#define AR5K_2W_TX_DESC_CTL1_NOACK 0x00800000 /*[5211]*/ -#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION 0xfff80000 /*[5210 ?]*/ + AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_5210 : \ + AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_5211) +#define AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX_S 13 +#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211 0x00700000 /* [5211] frame type */ +#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211_S 20 +#define AR5K_2W_TX_DESC_CTL1_NOACK_5211 0x00800000 /* [5211] no ACK */ +#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION_5210 0xfff80000 /* [5210] lower 13 bit of duration */ /* Frame types */ -#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL 0x00 -#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM 0x04 -#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL 0x08 -#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c -#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 0x10 +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL 0 +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM 1 +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL 2 +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 3 +#define AR5K_AR5211_TX_DESC_FRAME_TYPE_BEACON 3 +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 4 +#define AR5K_AR5211_TX_DESC_FRAME_TYPE_PRESP 4 /* * 5212 hardware 4-word TX control descriptor */ struct ath5k_hw_4w_tx_ctl { u32 tx_control_0; /* TX control word 0 */ + u32 tx_control_1; /* TX control word 1 */ + u32 tx_control_2; /* TX control word 2 */ + u32 tx_control_3; /* TX control word 3 */ +} __packed; -#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff -#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER 0x003f0000 +/* TX control word 0 fields/flags */ +#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff /* frame length */ +#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER 0x003f0000 /* transmit power */ #define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S 16 -#define AR5K_4W_TX_DESC_CTL0_RTSENA 0x00400000 -#define AR5K_4W_TX_DESC_CTL0_VEOL 0x00800000 -#define AR5K_4W_TX_DESC_CTL0_CLRDMASK 0x01000000 -#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT 0x1e000000 +#define AR5K_4W_TX_DESC_CTL0_RTSENA 0x00400000 /* RTS/CTS enable */ +#define AR5K_4W_TX_DESC_CTL0_VEOL 0x00800000 /* virtual end-of-list */ +#define AR5K_4W_TX_DESC_CTL0_CLRDMASK 0x01000000 /* clear destination mask */ +#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT 0x1e000000 /* TX antenna selection */ #define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25 -#define AR5K_4W_TX_DESC_CTL0_INTREQ 0x20000000 -#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 -#define AR5K_4W_TX_DESC_CTL0_CTSENA 0x80000000 - - u32 tx_control_1; /* TX control word 1 */ +#define AR5K_4W_TX_DESC_CTL0_INTREQ 0x20000000 /* TX interrupt request */ +#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 /* destination index valid */ +#define AR5K_4W_TX_DESC_CTL0_CTSENA 0x80000000 /* precede frame with CTS */ -#define AR5K_4W_TX_DESC_CTL1_BUF_LEN 0x00000fff -#define AR5K_4W_TX_DESC_CTL1_MORE 0x00001000 -#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX 0x000fe000 -#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13 -#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE 0x00f00000 +/* TX control word 1 fields/flags */ +#define AR5K_4W_TX_DESC_CTL1_BUF_LEN 0x00000fff /* data buffer length */ +#define AR5K_4W_TX_DESC_CTL1_MORE 0x00001000 /* more desc for this frame */ +#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX 0x000fe000 /* destination table index */ +#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX_S 13 +#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE 0x00f00000 /* frame type */ #define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S 20 -#define AR5K_4W_TX_DESC_CTL1_NOACK 0x01000000 -#define AR5K_4W_TX_DESC_CTL1_COMP_PROC 0x06000000 +#define AR5K_4W_TX_DESC_CTL1_NOACK 0x01000000 /* no ACK */ +#define AR5K_4W_TX_DESC_CTL1_COMP_PROC 0x06000000 /* compression processing */ #define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S 25 -#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN 0x18000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN 0x18000000 /* length of frame IV */ #define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S 27 -#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN 0x60000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN 0x60000000 /* length of frame ICV */ #define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S 29 - u32 tx_control_2; /* TX control word 2 */ - -#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION 0x00007fff -#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE 0x00008000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0 0x000f0000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S 16 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1 0x00f00000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S 20 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2 0x0f000000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S 24 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3 0xf0000000 -#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S 28 - - u32 tx_control_3; /* TX control word 3 */ - -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0 0x0000001f -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1 0x000003e0 +/* TX control word 2 fields/flags */ +#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION 0x00007fff /* RTS/CTS duration */ +#define AR5K_4W_TX_DESC_CTL2_DURATION_UPD_EN 0x00008000 /* frame duration update */ +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0 0x000f0000 /* series 0 max attempts */ +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S 16 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1 0x00f00000 /* series 1 max attempts */ +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S 20 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2 0x0f000000 /* series 2 max attempts */ +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S 24 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3 0xf0000000 /* series 3 max attempts */ +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S 28 + +/* TX control word 3 fields/flags */ +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0 0x0000001f /* series 0 tx rate */ +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1 0x000003e0 /* series 1 tx rate */ #define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S 5 -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2 0x00007c00 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2 0x00007c00 /* series 2 tx rate */ #define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S 10 -#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3 0x000f8000 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3 0x000f8000 /* series 3 tx rate */ #define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S 15 -#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000 +#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000 /* RTS or CTS rate */ #define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S 20 -} __packed; /* * Common TX status descriptor @@ -264,37 +247,34 @@ struct ath5k_hw_tx_status { } __packed; /* TX status word 0 fields/flags */ -#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK 0x00000001 -#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES 0x00000002 -#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN 0x00000004 -#define AR5K_DESC_TX_STATUS0_FILTERED 0x00000008 -/*??? -#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT 0x000000f0 -#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S 4 -*/ -#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT 0x000000f0 +#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK 0x00000001 /* TX success */ +#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES 0x00000002 /* excessive retries */ +#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN 0x00000004 /* FIFO underrun */ +#define AR5K_DESC_TX_STATUS0_FILTERED 0x00000008 /* TX filter indication */ +/* according to the HAL sources the spec has short/long retry counts reversed. + * we have it reversed to the HAL sources as well, for 5210 and 5211. + * For 5212 these fields are defined as RTS_FAIL_COUNT and DATA_FAIL_COUNT, + * but used respectively as SHORT and LONG retry count in the code later. This + * is consistent with the definitions here... TODO: check */ +#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT 0x000000f0 /* short retry count */ #define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S 4 -/*??? -#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT 0x00000f00 -#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S 8 -*/ -#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT 0x00000f00 +#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT 0x00000f00 /* long retry count */ #define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S 8 -#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT 0x0000f000 -#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S 12 -#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP 0xffff0000 +#define AR5K_DESC_TX_STATUS0_VIRTCOLL_CT_5211 0x0000f000 /* [5211+] virtual collision count */ +#define AR5K_DESC_TX_STATUS0_VIRTCOLL_CT_5212_S 12 +#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP 0xffff0000 /* TX timestamp */ #define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S 16 /* TX status word 1 fields/flags */ -#define AR5K_DESC_TX_STATUS1_DONE 0x00000001 -#define AR5K_DESC_TX_STATUS1_SEQ_NUM 0x00001ffe +#define AR5K_DESC_TX_STATUS1_DONE 0x00000001 /* descriptor complete */ +#define AR5K_DESC_TX_STATUS1_SEQ_NUM 0x00001ffe /* TX sequence number */ #define AR5K_DESC_TX_STATUS1_SEQ_NUM_S 1 -#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH 0x001fe000 +#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH 0x001fe000 /* signal strength of ACK */ #define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S 13 -#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX 0x00600000 -#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S 21 -#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS 0x00800000 -#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA 0x01000000 +#define AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212 0x00600000 /* [5212] final TX attempt series ix */ +#define AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212_S 21 +#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS_5212 0x00800000 /* [5212] compression status */ +#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212 0x01000000 /* [5212] transmit antenna */ /* * 5210/5211 hardware TX descriptor @@ -313,18 +293,15 @@ struct ath5k_hw_5212_tx_desc { } __packed; /* - * common hardware RX descriptor + * Common hardware RX descriptor */ struct ath5k_hw_all_rx_desc { - struct ath5k_hw_rx_ctl rx_ctl; - union { - struct ath5k_hw_rx_status rx_stat; - struct ath5k_hw_rx_error rx_err; - } u; + struct ath5k_hw_rx_ctl rx_ctl; + struct ath5k_hw_rx_status rx_stat; } __packed; /* - * Atheros hardware descriptor + * Atheros hardware DMA descriptor * This is read and written to by the hardware */ struct ath5k_desc { @@ -346,4 +323,3 @@ struct ath5k_desc { #define AR5K_TXDESC_CTSENA 0x0008 #define AR5K_TXDESC_INTREQ 0x0010 #define AR5K_TXDESC_VEOL 0x0020 /*[5211+]*/ - diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index 941b51130a6f..923c9ca5c4f0 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -48,7 +48,6 @@ */ void ath5k_hw_start_rx_dma(struct ath5k_hw *ah) { - ATH5K_TRACE(ah->ah_sc); ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR); ath5k_hw_reg_read(ah, AR5K_CR); } @@ -62,7 +61,6 @@ int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) { unsigned int i; - ATH5K_TRACE(ah->ah_sc); ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR); /* @@ -96,8 +94,6 @@ u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah) */ void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr) { - ATH5K_TRACE(ah->ah_sc); - ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP); } @@ -125,7 +121,6 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) { u32 tx_queue; - ATH5K_TRACE(ah->ah_sc); AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); /* Return if queue is declared inactive */ @@ -186,7 +181,6 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) unsigned int i = 40; u32 tx_queue, pending; - ATH5K_TRACE(ah->ah_sc); AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); /* Return if queue is declared inactive */ @@ -250,7 +244,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) /* Force channel idle high */ AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211, - AR5K_DIAG_SW_CHANEL_IDLE_HIGH); + AR5K_DIAG_SW_CHANNEL_IDLE_HIGH); /* Wait a while and disable mechanism */ udelay(200); @@ -267,7 +261,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) } while (--i && pending); AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211, - AR5K_DIAG_SW_CHANEL_IDLE_HIGH); + AR5K_DIAG_SW_CHANNEL_IDLE_HIGH); } /* Clear register */ @@ -297,7 +291,6 @@ u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue) { u16 tx_reg; - ATH5K_TRACE(ah->ah_sc); AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); /* @@ -340,7 +333,6 @@ int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) { u16 tx_reg; - ATH5K_TRACE(ah->ah_sc); AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); /* @@ -385,11 +377,11 @@ int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) * * This function increases/decreases the tx trigger level for the tx fifo * buffer (aka FIFO threshold) that is used to indicate when PCU flushes - * the buffer and transmits it's data. Lowering this results sending small + * the buffer and transmits its data. Lowering this results sending small * frames more quickly but can lead to tx underruns, raising it a lot can * result other problems (i think bmiss is related). Right now we start with * the lowest possible (64Bytes) and if we get tx underrun we increase it using - * the increase flag. Returns -EIO if we have have reached maximum/minimum. + * the increase flag. Returns -EIO if we have reached maximum/minimum. * * XXX: Link this with tx DMA size ? * XXX: Use it to save interrupts ? @@ -400,8 +392,6 @@ int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase) u32 trigger_level, imr; int ret = -EIO; - ATH5K_TRACE(ah->ah_sc); - /* * Disable interrupts by setting the mask */ @@ -451,7 +441,6 @@ done: */ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) { - ATH5K_TRACE(ah->ah_sc); return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0; } @@ -475,8 +464,6 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) { u32 data; - ATH5K_TRACE(ah->ah_sc); - /* * Read interrupt status from the Interrupt Status register * on 5210 diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index ed0263672d6d..39722dd73e43 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -35,7 +35,6 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data) { u32 status, timeout; - ATH5K_TRACE(ah->ah_sc); /* * Initialize EEPROM access */ @@ -662,7 +661,7 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) * (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC * steps that match with the power values we read from eeprom. On * older eeprom versions (< 3.2) these steps are equaly spaced at - * 10% of the pcdac curve -until the curve reaches it's maximum- + * 10% of the pcdac curve -until the curve reaches its maximum- * (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2) * these 11 steps are spaced in a different way. This function returns * the pcdac steps based on eeprom version and curve min/max so that we @@ -715,7 +714,7 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, /* Only one curve for RF5111 * find out which one and place - * in in pd_curves. + * in pd_curves. * Note: ee_x_gain is reversed here */ for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) { @@ -1114,7 +1113,7 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) */ /* For RF2413 power calibration data doesn't start on a fixed location and - * if a mode is not supported, it's section is missing -not zeroed-. + * if a mode is not supported, its section is missing -not zeroed-. * So we need to calculate the starting offset for each section by using * these two functions */ diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c index 64a27e73d02e..bc90503f4b7a 100644 --- a/drivers/net/wireless/ath/ath5k/gpio.c +++ b/drivers/net/wireless/ath/ath5k/gpio.c @@ -34,8 +34,6 @@ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) /*5210 has different led mode handling*/ u32 led_5210; - ATH5K_TRACE(ah->ah_sc); - /*Reset led status*/ if (ah->ah_version != AR5K_AR5210) AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, @@ -82,7 +80,6 @@ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) */ int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) { - ATH5K_TRACE(ah->ah_sc); if (gpio >= AR5K_NUM_GPIO) return -EINVAL; @@ -98,7 +95,6 @@ int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) */ int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) { - ATH5K_TRACE(ah->ah_sc); if (gpio >= AR5K_NUM_GPIO) return -EINVAL; @@ -114,7 +110,6 @@ int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) */ u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) { - ATH5K_TRACE(ah->ah_sc); if (gpio >= AR5K_NUM_GPIO) return 0xffffffff; @@ -129,7 +124,6 @@ u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) { u32 data; - ATH5K_TRACE(ah->ah_sc); if (gpio >= AR5K_NUM_GPIO) return -EINVAL; @@ -153,7 +147,6 @@ void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, { u32 data; - ATH5K_TRACE(ah->ah_sc); if (gpio >= AR5K_NUM_GPIO) return; diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 5212e275f1c7..074b4c644399 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -59,8 +59,6 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) beacon_reg = 0; - ATH5K_TRACE(ah->ah_sc); - switch (op_mode) { case NL80211_IFTYPE_ADHOC: pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE; @@ -139,11 +137,11 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah) * ath5k_hw_set_ack_bitrate - set bitrate for ACKs * * @ah: The &struct ath5k_hw - * @high: Flag to determine if we want to use high transmition rate + * @high: Flag to determine if we want to use high transmission rate * for ACKs or not * * If high flag is set, we tell hw to use a set of control rates based on - * the current transmition rate (check out control_rates array inside reset.c). + * the current transmission rate (check out control_rates array inside reset.c). * If not hw just uses the lowest rate available for the current modulation * scheme being used (1Mbit for CCK and 6Mbits for OFDM). */ @@ -173,7 +171,6 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) */ static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) { - ATH5K_TRACE(ah->ah_sc); if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK)) <= timeout) return -EINVAL; @@ -192,7 +189,6 @@ static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) */ static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) { - ATH5K_TRACE(ah->ah_sc); if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS)) <= timeout) return -EINVAL; @@ -211,7 +207,8 @@ static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) */ unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) { - return usec * ath5k_hw_get_clockrate(ah); + struct ath_common *common = ath5k_hw_common(ah); + return usec * common->clockrate; } /** @@ -220,17 +217,19 @@ unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) */ unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) { - return clock / ath5k_hw_get_clockrate(ah); + struct ath_common *common = ath5k_hw_common(ah); + return clock / common->clockrate; } /** - * ath5k_hw_get_clockrate - Get the clock rate for current mode + * ath5k_hw_set_clockrate - Set common->clockrate for the current channel * * @ah: The &struct ath5k_hw */ -unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah) +void ath5k_hw_set_clockrate(struct ath5k_hw *ah) { struct ieee80211_channel *channel = ah->ah_current_channel; + struct ath_common *common = ath5k_hw_common(ah); int clock; if (channel->hw_value & CHANNEL_5GHZ) @@ -244,7 +243,7 @@ unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah) if (channel->hw_value & CHANNEL_TURBO) clock *= 2; - return clock; + common->clockrate = clock; } /** @@ -297,7 +296,6 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) u32 low_id, high_id; u32 pcu_reg; - ATH5K_TRACE(ah->ah_sc); /* Set new station ID */ memcpy(common->macaddr, mac, ETH_ALEN); @@ -313,27 +311,26 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) } /** - * ath5k_hw_set_associd - Set BSSID for association + * ath5k_hw_set_bssid - Set current BSSID on hw * * @ah: The &struct ath5k_hw - * @bssid: BSSID - * @assoc_id: Assoc id * - * Sets the BSSID which trigers the "SME Join" operation + * Sets the current BSSID and BSSID mask we have from the + * common struct into the hardware */ -void ath5k_hw_set_associd(struct ath5k_hw *ah) +void ath5k_hw_set_bssid(struct ath5k_hw *ah) { struct ath_common *common = ath5k_hw_common(ah); u16 tim_offset = 0; /* - * Set simple BSSID mask on 5212 + * Set BSSID mask on 5212 */ if (ah->ah_version == AR5K_AR5212) ath_hw_setbssidmask(common); /* - * Set BSSID which triggers the "SME Join" operation + * Set BSSID */ ath5k_hw_reg_write(ah, get_unaligned_le32(common->curbssid), @@ -357,7 +354,6 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah) void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) { struct ath_common *common = ath5k_hw_common(ah); - ATH5K_TRACE(ah->ah_sc); /* Cache bssid mask so that we can restore it * on reset */ @@ -382,7 +378,6 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) */ void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) { - ATH5K_TRACE(ah->ah_sc); AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); } @@ -397,7 +392,6 @@ void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) */ void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) { - ATH5K_TRACE(ah->ah_sc); AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); } @@ -406,8 +400,6 @@ void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) */ void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) { - ATH5K_TRACE(ah->ah_sc); - /* Set the multicat filter */ ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0); ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); } @@ -427,7 +419,6 @@ u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) { u32 data, filter = 0; - ATH5K_TRACE(ah->ah_sc); filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER); /*Radar detection for 5212*/ @@ -457,8 +448,6 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) { u32 data = 0; - ATH5K_TRACE(ah->ah_sc); - /* Set PHY error filter register on 5212*/ if (ah->ah_version == AR5K_AR5212) { if (filter & AR5K_RX_FILTER_RADARERR) @@ -509,6 +498,10 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) { u32 tsf_lower, tsf_upper1, tsf_upper2; int i; + unsigned long flags; + + /* This code is time critical - we don't want to be interrupted here */ + local_irq_save(flags); /* * While reading TSF upper and then lower part, the clock is still @@ -531,9 +524,9 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) tsf_upper1 = tsf_upper2; } - WARN_ON( i == ATH5K_MAX_TSF_READ ); + local_irq_restore(flags); - ATH5K_TRACE(ah->ah_sc); + WARN_ON( i == ATH5K_MAX_TSF_READ ); return (((u64)tsf_upper1 << 32) | tsf_lower); } @@ -548,8 +541,6 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) */ void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64) { - ATH5K_TRACE(ah->ah_sc); - ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32); ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32); } @@ -565,8 +556,6 @@ void ath5k_hw_reset_tsf(struct ath5k_hw *ah) { u32 val; - ATH5K_TRACE(ah->ah_sc); - val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF; /* @@ -586,7 +575,6 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) { u32 timer1, timer2, timer3; - ATH5K_TRACE(ah->ah_sc); /* * Set the additional timers by mode */ @@ -621,7 +609,7 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) /* Timer3 marks the end of our ATIM window * a zero length window is not allowed because * we 'll get no beacons */ - timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); + timer3 = next_beacon + 1; /* * Set the beacon register and enable all timers. @@ -661,202 +649,95 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) } - -/*********************\ -* Key table functions * -\*********************/ - -/* - * Reset a key entry on the table +/** + * ath5k_check_timer_win - Check if timer B is timer A + window + * + * @a: timer a (before b) + * @b: timer b (after a) + * @window: difference between a and b + * @intval: timers are increased by this interval + * + * This helper function checks if timer B is timer A + window and covers + * cases where timer A or B might have already been updated or wrapped + * around (Timers are 16 bit). + * + * Returns true if O.K. */ -int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) +static inline bool +ath5k_check_timer_win(int a, int b, int window, int intval) { - unsigned int i, type; - u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; - - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); - - type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry)); - - for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) - ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); - - /* Reset associated MIC entry if TKIP - * is enabled located at offset (entry + 64) */ - if (type == AR5K_KEYTABLE_TYPE_TKIP) { - AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE); - for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++) - ath5k_hw_reg_write(ah, 0, - AR5K_KEYTABLE_OFF(micentry, i)); - } - /* - * Set NULL encryption on AR5212+ - * - * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5) - * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007 - * - * Note2: Windows driver (ndiswrapper) sets this to - * 0x00000714 instead of 0x00000007 + * 1.) usually B should be A + window + * 2.) A already updated, B not updated yet + * 3.) A already updated and has wrapped around + * 4.) B has wrapped around */ - if (ah->ah_version >= AR5K_AR5211) { - ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, - AR5K_KEYTABLE_TYPE(entry)); - - if (type == AR5K_KEYTABLE_TYPE_TKIP) { - ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, - AR5K_KEYTABLE_TYPE(micentry)); - } - } - - return 0; -} - -static -int ath5k_keycache_type(const struct ieee80211_key_conf *key) -{ - switch (key->alg) { - case ALG_TKIP: - return AR5K_KEYTABLE_TYPE_TKIP; - case ALG_CCMP: - return AR5K_KEYTABLE_TYPE_CCM; - case ALG_WEP: - if (key->keylen == WLAN_KEY_LEN_WEP40) - return AR5K_KEYTABLE_TYPE_40; - else if (key->keylen == WLAN_KEY_LEN_WEP104) - return AR5K_KEYTABLE_TYPE_104; - return -EINVAL; - default: - return -EINVAL; - } - return -EINVAL; + if ((b - a == window) || /* 1.) */ + (a - b == intval - window) || /* 2.) */ + ((a | 0x10000) - b == intval - window) || /* 3.) */ + ((b | 0x10000) - a == window)) /* 4.) */ + return true; /* O.K. */ + return false; } -/* - * Set a key entry on the table +/** + * ath5k_hw_check_beacon_timers - Check if the beacon timers are correct + * + * @ah: The &struct ath5k_hw + * @intval: beacon interval + * + * This is a workaround for IBSS mode: + * + * The need for this function arises from the fact that we have 4 separate + * HW timer registers (TIMER0 - TIMER3), which are closely related to the + * next beacon target time (NBTT), and that the HW updates these timers + * seperately based on the current TSF value. The hardware increments each + * timer by the beacon interval, when the local TSF coverted to TU is equal + * to the value stored in the timer. + * + * The reception of a beacon with the same BSSID can update the local HW TSF + * at any time - this is something we can't avoid. If the TSF jumps to a + * time which is later than the time stored in a timer, this timer will not + * be updated until the TSF in TU wraps around at 16 bit (the size of the + * timers) and reaches the time which is stored in the timer. + * + * The problem is that these timers are closely related to TIMER0 (NBTT) and + * that they define a time "window". When the TSF jumps between two timers + * (e.g. ATIM and NBTT), the one in the past will be left behind (not + * updated), while the one in the future will be updated every beacon + * interval. This causes the window to get larger, until the TSF wraps + * around as described above and the timer which was left behind gets + * updated again. But - because the beacon interval is usually not an exact + * divisor of the size of the timers (16 bit), an unwanted "window" between + * these timers has developed! + * + * This is especially important with the ATIM window, because during + * the ATIM window only ATIM frames and no data frames are allowed to be + * sent, which creates transmission pauses after each beacon. This symptom + * has been described as "ramping ping" because ping times increase linearly + * for some time and then drop down again. A wrong window on the DMA beacon + * timer has the same effect, so we check for these two conditions. + * + * Returns true if O.K. */ -int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, - const struct ieee80211_key_conf *key, const u8 *mac) -{ - unsigned int i; - int keylen; - __le32 key_v[5] = {}; - __le32 key0 = 0, key1 = 0; - __le32 *rxmic, *txmic; - int keytype; - u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; - bool is_tkip; - const u8 *key_ptr; - - ATH5K_TRACE(ah->ah_sc); - - is_tkip = (key->alg == ALG_TKIP); - - /* - * key->keylen comes in from mac80211 in bytes. - * TKIP is 128 bit + 128 bit mic - */ - keylen = (is_tkip) ? (128 / 8) : key->keylen; - - if (entry > AR5K_KEYTABLE_SIZE || - (is_tkip && micentry > AR5K_KEYTABLE_SIZE)) - return -EOPNOTSUPP; - - if (unlikely(keylen > 16)) - return -EOPNOTSUPP; - - keytype = ath5k_keycache_type(key); - if (keytype < 0) - return keytype; - - /* - * each key block is 6 bytes wide, written as pairs of - * alternating 32 and 16 bit le values. - */ - key_ptr = key->key; - for (i = 0; keylen >= 6; keylen -= 6) { - memcpy(&key_v[i], key_ptr, 6); - i += 2; - key_ptr += 6; - } - if (keylen) - memcpy(&key_v[i], key_ptr, keylen); - - /* intentionally corrupt key until mic is installed */ - if (is_tkip) { - key0 = key_v[0] = ~key_v[0]; - key1 = key_v[1] = ~key_v[1]; - } - - for (i = 0; i < ARRAY_SIZE(key_v); i++) - ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), - AR5K_KEYTABLE_OFF(entry, i)); - - ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); - - if (is_tkip) { - /* Install rx/tx MIC */ - rxmic = (__le32 *) &key->key[16]; - txmic = (__le32 *) &key->key[24]; - - if (ah->ah_combined_mic) { - key_v[0] = rxmic[0]; - key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16); - key_v[2] = rxmic[1]; - key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff); - key_v[4] = txmic[1]; - } else { - key_v[0] = rxmic[0]; - key_v[1] = 0; - key_v[2] = rxmic[1]; - key_v[3] = 0; - key_v[4] = 0; - } - for (i = 0; i < ARRAY_SIZE(key_v); i++) - ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), - AR5K_KEYTABLE_OFF(micentry, i)); - - ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, - AR5K_KEYTABLE_TYPE(micentry)); - ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry)); - ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry)); - - /* restore first 2 words of key */ - ath5k_hw_reg_write(ah, le32_to_cpu(~key0), - AR5K_KEYTABLE_OFF(entry, 0)); - ath5k_hw_reg_write(ah, le32_to_cpu(~key1), - AR5K_KEYTABLE_OFF(entry, 1)); - } - - return ath5k_hw_set_key_lladdr(ah, entry, mac); -} - -int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) +bool +ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval) { - u32 low_id, high_id; + unsigned int nbtt, atim, dma; - ATH5K_TRACE(ah->ah_sc); - /* Invalid entry (key table overflow) */ - AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + nbtt = ath5k_hw_reg_read(ah, AR5K_TIMER0); + atim = ath5k_hw_reg_read(ah, AR5K_TIMER3); + dma = ath5k_hw_reg_read(ah, AR5K_TIMER1) >> 3; - /* - * MAC may be NULL if it's a broadcast key. In this case no need to - * to compute get_unaligned_le32 and get_unaligned_le16 as we - * already know it. - */ - if (!mac) { - low_id = 0xffffffff; - high_id = 0xffff | AR5K_KEYTABLE_VALID; - } else { - low_id = get_unaligned_le32(mac); - high_id = get_unaligned_le16(mac + 4) | AR5K_KEYTABLE_VALID; - } + /* NOTE: SWBA is different. Having a wrong window there does not + * stop us from sending data and this condition is catched thru + * other means (SWBA interrupt) */ - ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry)); - ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry)); - - return 0; + if (ath5k_check_timer_win(nbtt, atim, 1, intval) && + ath5k_check_timer_win(dma, nbtt, AR5K_TUNE_DMA_BEACON_RESP, + intval)) + return true; /* O.K. */ + return false; } /** diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 492cbb15720d..219367884e64 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -115,7 +115,7 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah, \**********************/ /* - * This code is used to optimize rf gain on different environments + * This code is used to optimize RF gain on different environments * (temperature mostly) based on feedback from a power detector. * * It's only used on RF5111 and RF5112, later RF chips seem to have @@ -302,7 +302,7 @@ static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) } /* Perform gain_F adjustment by choosing the right set - * of parameters from rf gain optimization ladder */ + * of parameters from RF gain optimization ladder */ static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah) { const struct ath5k_gain_opt *go; @@ -367,7 +367,7 @@ done: return ret; } -/* Main callback for thermal rf gain calibration engine +/* Main callback for thermal RF gain calibration engine * Check for a new gain reading and schedule an adjustment * if needed. * @@ -378,8 +378,6 @@ enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah) u32 data, type; struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - ATH5K_TRACE(ah->ah_sc); - if (ah->ah_rf_banks == NULL || ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE) return AR5K_RFGAIN_INACTIVE; @@ -435,7 +433,7 @@ done: return ah->ah_gain.g_state; } -/* Write initial rf gain table to set the RF sensitivity +/* Write initial RF gain table to set the RF sensitivity * this one works on all RF chips and has nothing to do * with gain_F calibration */ int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq) @@ -498,7 +496,7 @@ int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq) /* - * Setup RF registers by writing rf buffer on hw + * Setup RF registers by writing RF buffer on hw */ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode) @@ -573,7 +571,7 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, return -EINVAL; } - /* If it's the first time we set rf buffer, allocate + /* If it's the first time we set RF buffer, allocate * ah->ah_rf_banks based on ah->ah_rf_banks_size * we set above */ if (ah->ah_rf_banks == NULL) { @@ -1095,6 +1093,7 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) ah->ah_current_channel = channel; ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false; + ath5k_hw_set_clockrate(ah); return 0; } @@ -1167,7 +1166,7 @@ static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah) * The median of the values in the history is then loaded into the * hardware for its own use for RSSI and CCA measurements. */ -static void ath5k_hw_update_noise_floor(struct ath5k_hw *ah) +void ath5k_hw_update_noise_floor(struct ath5k_hw *ah) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; u32 val; @@ -1248,7 +1247,6 @@ static void ath5k_hw_update_noise_floor(struct ath5k_hw *ah) /* * Perform a PHY calibration on RF5110 * -Fix BPSK/QAM Constellation (I/Q correction) - * -Calculate Noise Floor */ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel) @@ -1260,7 +1258,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, * Disable beacons and RX/TX queues, wait */ AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210, - AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); + AR5K_DIAG_SW_DIS_TX_5210 | AR5K_DIAG_SW_DIS_RX_5210); beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); @@ -1335,35 +1333,31 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, return ret; } - ath5k_hw_update_noise_floor(ah); - /* * Re-enable RX/TX and beacons */ AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210, - AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); + AR5K_DIAG_SW_DIS_TX_5210 | AR5K_DIAG_SW_DIS_RX_5210); ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210); return 0; } /* - * Perform a PHY calibration on RF5111/5112 and newer chips + * Perform I/Q calibration on RF5111/5112 and newer chips */ -static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, - struct ieee80211_channel *channel) +static int +ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah) { u32 i_pwr, q_pwr; s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd; int i; - ATH5K_TRACE(ah->ah_sc); if (!ah->ah_calibration || ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) - goto done; + return 0; /* Calibration has finished, get the results and re-run */ - /* work around empty results which can apparently happen on 5212 */ for (i = 0; i <= 10; i++) { iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); @@ -1384,7 +1378,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, /* protect against divide by 0 and loss of sign bits */ if (i_coffd == 0 || q_coffd < 2) - goto done; + return 0; i_coff = (-iq_corr) / i_coffd; i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */ @@ -1410,17 +1404,6 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN); -done: - - /* TODO: Separate noise floor calibration from I/Q calibration - * since noise floor calibration interrupts rx path while I/Q - * calibration doesn't. We don't need to run noise floor calibration - * as often as I/Q calibration.*/ - ath5k_hw_update_noise_floor(ah); - - /* Initiate a gain_F calibration */ - ath5k_hw_request_rfgain_probe(ah); - return 0; } @@ -1434,8 +1417,10 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, if (ah->ah_radio == AR5K_RF5110) ret = ath5k_hw_rf5110_calibrate(ah, channel); - else - ret = ath5k_hw_rf511x_calibrate(ah, channel); + else { + ret = ath5k_hw_rf511x_iq_calibrate(ah); + ath5k_hw_request_rfgain_probe(ah); + } return ret; } @@ -1598,7 +1583,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, else if (curr_sym_off >= 31 && curr_sym_off <= 46) mag_mask[2] |= plt_mag_map << (curr_sym_off - 31) * 2; - else if (curr_sym_off >= 46 && curr_sym_off <= 53) + else if (curr_sym_off >= 47 && curr_sym_off <= 53) mag_mask[3] |= plt_mag_map << (curr_sym_off - 47) * 2; @@ -1693,7 +1678,6 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, int ath5k_hw_phy_disable(struct ath5k_hw *ah) { - ATH5K_TRACE(ah->ah_sc); /*Just a try M.F.*/ ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); @@ -1709,8 +1693,6 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) u32 srev; u16 ret; - ATH5K_TRACE(ah->ah_sc); - /* * Set the radio chip access register */ @@ -1755,8 +1737,6 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) static void /*TODO:Boundary check*/ ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant) { - ATH5K_TRACE(ah->ah_sc); - if (ah->ah_version != AR5K_AR5210) ath5k_hw_reg_write(ah, ant & 0x7, AR5K_DEFAULT_ANTENNA); } @@ -1789,19 +1769,50 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable) if (enable) { AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART, - AR5K_PHY_RESTART_DIV_GC, 0xc); + AR5K_PHY_RESTART_DIV_GC, 4); AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV, AR5K_PHY_FAST_ANT_DIV_EN); } else { AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RESTART, - AR5K_PHY_RESTART_DIV_GC, 0x8); + AR5K_PHY_RESTART_DIV_GC, 0); AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_FAST_ANT_DIV, AR5K_PHY_FAST_ANT_DIV_EN); } } +void +ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode) +{ + u8 ant0, ant1; + + /* + * In case a fixed antenna was set as default + * use the same switch table twice. + */ + if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_A) + ant0 = ant1 = AR5K_ANT_SWTABLE_A; + else if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_B) + ant0 = ant1 = AR5K_ANT_SWTABLE_B; + else { + ant0 = AR5K_ANT_SWTABLE_A; + ant1 = AR5K_ANT_SWTABLE_B; + } + + /* Set antenna idle switch table */ + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL, + AR5K_PHY_ANT_CTL_SWTABLE_IDLE, + (ah->ah_ant_ctl[ee_mode][AR5K_ANT_CTL] | + AR5K_PHY_ANT_CTL_TXRX_EN)); + + /* Set antenna switch tables */ + ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant0], + AR5K_PHY_ANT_SWITCH_TABLE_0); + ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant1], + AR5K_PHY_ANT_SWITCH_TABLE_1); +} + /* * Set antenna operating mode */ @@ -1823,8 +1834,6 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) def_ant = ah->ah_def_ant; - ATH5K_TRACE(ah->ah_sc); - switch (channel->hw_value & CHANNEL_MODES) { case CHANNEL_A: case CHANNEL_T: @@ -1923,6 +1932,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) if (sta_id1) AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, sta_id1); + ath5k_hw_set_antenna_switch(ah, ee_mode); /* Note: set diversity before default antenna * because it won't work correctly */ ath5k_hw_set_fast_div(ah, ee_mode, fast_div); @@ -2978,7 +2988,7 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr, /* - * Set transmition power + * Set transmission power */ int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, @@ -2988,7 +2998,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, u8 type; int ret; - ATH5K_TRACE(ah->ah_sc); if (txpower > AR5K_TUNE_MAX_TXPOWER) { ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); return -EINVAL; @@ -3027,9 +3036,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, /* Limit max power if we have a CTL available */ ath5k_get_max_ctl_power(ah, channel); - /* FIXME: Tx power limit for this regdomain - * XXX: Mac80211/CRDA will do that anyway ? */ - /* FIXME: Antenna reduction stuff */ /* FIXME: Limit power on turbo modes */ @@ -3084,8 +3090,6 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) struct ieee80211_channel *channel = ah->ah_current_channel; u8 ee_mode; - ATH5K_TRACE(ah->ah_sc); - switch (channel->hw_value & CHANNEL_MODES) { case CHANNEL_A: case CHANNEL_T: diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index f5831da33f7b..84c717ded1c5 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -31,31 +31,63 @@ Queue Control Unit, DFS Control Unit Functions int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info) { - ATH5K_TRACE(ah->ah_sc); memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info)); return 0; } /* + * Make sure cw is a power of 2 minus 1 and smaller than 1024 + */ +static u16 ath5k_cw_validate(u16 cw_req) +{ + u32 cw = 1; + cw_req = min(cw_req, (u16)1023); + + while (cw < cw_req) + cw = (cw << 1) | 1; + + return cw; +} + +/* * Set properties for a transmit queue */ int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, - const struct ath5k_txq_info *queue_info) + const struct ath5k_txq_info *qinfo) { - ATH5K_TRACE(ah->ah_sc); + struct ath5k_txq_info *qi; + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) + qi = &ah->ah_txq[queue]; + + if (qi->tqi_type == AR5K_TX_QUEUE_INACTIVE) return -EIO; - memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info)); + /* copy and validate values */ + qi->tqi_type = qinfo->tqi_type; + qi->tqi_subtype = qinfo->tqi_subtype; + qi->tqi_flags = qinfo->tqi_flags; + /* + * According to the docs: Although the AIFS field is 8 bit wide, + * the maximum supported value is 0xFC. Setting it higher than that + * will cause the DCU to hang. + */ + qi->tqi_aifs = min(qinfo->tqi_aifs, (u8)0xFC); + qi->tqi_cw_min = ath5k_cw_validate(qinfo->tqi_cw_min); + qi->tqi_cw_max = ath5k_cw_validate(qinfo->tqi_cw_max); + qi->tqi_cbr_period = qinfo->tqi_cbr_period; + qi->tqi_cbr_overflow_limit = qinfo->tqi_cbr_overflow_limit; + qi->tqi_burst_time = qinfo->tqi_burst_time; + qi->tqi_ready_time = qinfo->tqi_ready_time; /*XXX: Is this supported on 5210 ?*/ - if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA && - ((queue_info->tqi_subtype == AR5K_WME_AC_VI) || - (queue_info->tqi_subtype == AR5K_WME_AC_VO))) || - queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD) - ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS; + /*XXX: Is this correct for AR5K_WME_AC_VI,VO ???*/ + if ((qinfo->tqi_type == AR5K_TX_QUEUE_DATA && + ((qinfo->tqi_subtype == AR5K_WME_AC_VI) || + (qinfo->tqi_subtype == AR5K_WME_AC_VO))) || + qinfo->tqi_type == AR5K_TX_QUEUE_UAPSD) + qi->tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS; return 0; } @@ -69,8 +101,6 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, unsigned int queue; int ret; - ATH5K_TRACE(ah->ah_sc); - /* * Get queue by type */ @@ -149,7 +179,6 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) { u32 pending; - ATH5K_TRACE(ah->ah_sc); AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); /* Return if queue is declared inactive */ @@ -177,7 +206,6 @@ u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) */ void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) { - ATH5K_TRACE(ah->ah_sc); if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num)) return; @@ -192,10 +220,9 @@ void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) */ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) { - u32 cw_min, cw_max, retry_lg, retry_sh; + u32 retry_lg, retry_sh; struct ath5k_txq_info *tq = &ah->ah_txq[queue]; - ATH5K_TRACE(ah->ah_sc); AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); tq = &ah->ah_txq[queue]; @@ -224,14 +251,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) /* Set IFS0 */ if (ah->ah_turbo) { ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO + - (ah->ah_aifs + tq->tqi_aifs) * - AR5K_INIT_SLOT_TIME_TURBO) << + tq->tqi_aifs * AR5K_INIT_SLOT_TIME_TURBO) << AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO, AR5K_IFS0); } else { ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS + - (ah->ah_aifs + tq->tqi_aifs) * - AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) | + tq->tqi_aifs * AR5K_INIT_SLOT_TIME) << + AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS, AR5K_IFS0); } @@ -255,35 +281,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) } /* - * Calculate cwmin/max by channel mode - */ - cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN; - cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX; - ah->ah_aifs = AR5K_TUNE_AIFS; - /*XR is only supported on 5212*/ - if (IS_CHAN_XR(ah->ah_current_channel) && - ah->ah_version == AR5K_AR5212) { - cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR; - cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR; - ah->ah_aifs = AR5K_TUNE_AIFS_XR; - /*B mode is not supported on 5210*/ - } else if (IS_CHAN_B(ah->ah_current_channel) && - ah->ah_version != AR5K_AR5210) { - cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B; - cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B; - ah->ah_aifs = AR5K_TUNE_AIFS_11B; - } - - cw_min = 1; - while (cw_min < ah->ah_cw_min) - cw_min = (cw_min << 1) | 1; - - cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) : - ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1); - cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) : - ((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1); - - /* * Calculate and set retry limits */ if (ah->ah_software_retry) { @@ -299,7 +296,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) /*No QCU/DCU [5210]*/ if (ah->ah_version == AR5K_AR5210) { ath5k_hw_reg_write(ah, - (cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S) + (tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S) | AR5K_REG_SM(AR5K_INIT_SLG_RETRY, AR5K_NODCU_RETRY_LMT_SLG_RETRY) | AR5K_REG_SM(AR5K_INIT_SSH_RETRY, @@ -321,14 +318,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) /*===Rest is also for QCU/DCU only [5211+]===*/ /* - * Set initial content window (cw_min/cw_max) + * Set contention window (cw_min/cw_max) * and arbitrated interframe space (aifs)... */ ath5k_hw_reg_write(ah, - AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) | - AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) | - AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs, - AR5K_DCU_LCL_IFS_AIFS), + AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) | + AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) | + AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS), AR5K_QUEUE_DFS_LOCAL_IFS(queue)); /* @@ -523,8 +519,6 @@ int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) { u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time); - ATH5K_TRACE(ah->ah_sc); - if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX) return -EINVAL; diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 55b4ac6d236f..ca79ecd832fd 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -26,7 +26,6 @@ * Atheros presentations and papers like these: * * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf - * http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf * * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf * @@ -1387,10 +1386,9 @@ /* - * PCU control register + * PCU Diagnostic register * - * Only DIS_RX is used in the code, the rest i guess are - * for tweaking/diagnostics. + * Used for tweaking/diagnostics. */ #define AR5K_DIAG_SW_5210 0x8068 /* Register Address [5210] */ #define AR5K_DIAG_SW_5211 0x8048 /* Register Address [5211+] */ @@ -1399,22 +1397,22 @@ #define AR5K_DIAG_SW_DIS_WEP_ACK 0x00000001 /* Disable ACKs if WEP key is invalid */ #define AR5K_DIAG_SW_DIS_ACK 0x00000002 /* Disable ACKs */ #define AR5K_DIAG_SW_DIS_CTS 0x00000004 /* Disable CTSs */ -#define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable encryption */ -#define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable decryption */ -#define AR5K_DIAG_SW_DIS_TX 0x00000020 /* Disable transmit [5210] */ -#define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable recieve */ +#define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable HW encryption */ +#define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable HW decryption */ +#define AR5K_DIAG_SW_DIS_TX_5210 0x00000020 /* Disable transmit [5210] */ +#define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable receive */ #define AR5K_DIAG_SW_DIS_RX_5211 0x00000020 #define AR5K_DIAG_SW_DIS_RX (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211) -#define AR5K_DIAG_SW_LOOP_BACK_5210 0x00000080 /* Loopback (i guess it goes with DIS_TX) [5210] */ +#define AR5K_DIAG_SW_LOOP_BACK_5210 0x00000080 /* TX Data Loopback (i guess it goes with DIS_TX) [5210] */ #define AR5K_DIAG_SW_LOOP_BACK_5211 0x00000040 #define AR5K_DIAG_SW_LOOP_BACK (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211) -#define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 /* Corrupted FCS */ +#define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 /* Generate invalid TX FCS */ #define AR5K_DIAG_SW_CORR_FCS_5211 0x00000080 #define AR5K_DIAG_SW_CORR_FCS (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211) -#define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 /* Dump channel info */ +#define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 /* Add 56 bytes of channel info before the frame data in the RX buffer */ #define AR5K_DIAG_SW_CHAN_INFO_5211 0x00000100 #define AR5K_DIAG_SW_CHAN_INFO (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211) @@ -1426,17 +1424,17 @@ #define AR5K_DIAG_SW_SCVRAM_SEED 0x0003f800 /* [5210] */ #define AR5K_DIAG_SW_SCRAM_SEED_M 0x0001fc00 /* Scrambler seed mask */ #define AR5K_DIAG_SW_SCRAM_SEED_S 10 -#define AR5K_DIAG_SW_DIS_SEQ_INC 0x00040000 /* Disable seqnum increment (?)[5210] */ +#define AR5K_DIAG_SW_DIS_SEQ_INC_5210 0x00040000 /* Disable seqnum increment (?)[5210] */ #define AR5K_DIAG_SW_FRAME_NV0_5210 0x00080000 #define AR5K_DIAG_SW_FRAME_NV0_5211 0x00020000 /* Accept frames of non-zero protocol number */ #define AR5K_DIAG_SW_FRAME_NV0 (ah->ah_version == AR5K_AR5210 ? \ AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211) #define AR5K_DIAG_SW_OBSPT_M 0x000c0000 /* Observation point select (?) */ #define AR5K_DIAG_SW_OBSPT_S 18 -#define AR5K_DIAG_SW_RX_CLEAR_HIGH 0x0010000 /* Force RX Clear high */ -#define AR5K_DIAG_SW_IGNORE_CARR_SENSE 0x0020000 /* Ignore virtual carrier sense */ -#define AR5K_DIAG_SW_CHANEL_IDLE_HIGH 0x0040000 /* Force channel idle high */ -#define AR5K_DIAG_SW_PHEAR_ME 0x0080000 /* ??? */ +#define AR5K_DIAG_SW_RX_CLEAR_HIGH 0x00100000 /* Ignore carrier sense */ +#define AR5K_DIAG_SW_IGNORE_CARR_SENSE 0x00200000 /* Ignore virtual carrier sense */ +#define AR5K_DIAG_SW_CHANNEL_IDLE_HIGH 0x00400000 /* Force channel idle high */ +#define AR5K_DIAG_SW_PHEAR_ME 0x00800000 /* ??? */ /* * TSF (clock) register (lower 32 bits) @@ -1822,50 +1820,8 @@ /*===5212 end===*/ -/* - * Key table (WEP) register - */ -#define AR5K_KEYTABLE_0_5210 0x9000 -#define AR5K_KEYTABLE_0_5211 0x8800 -#define AR5K_KEYTABLE_5210(_n) (AR5K_KEYTABLE_0_5210 + ((_n) << 5)) -#define AR5K_KEYTABLE_5211(_n) (AR5K_KEYTABLE_0_5211 + ((_n) << 5)) -#define AR5K_KEYTABLE(_n) (ah->ah_version == AR5K_AR5210 ? \ - AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n)) -#define AR5K_KEYTABLE_OFF(_n, x) (AR5K_KEYTABLE(_n) + (x << 2)) -#define AR5K_KEYTABLE_TYPE(_n) AR5K_KEYTABLE_OFF(_n, 5) -#define AR5K_KEYTABLE_TYPE_40 0x00000000 -#define AR5K_KEYTABLE_TYPE_104 0x00000001 -#define AR5K_KEYTABLE_TYPE_128 0x00000003 -#define AR5K_KEYTABLE_TYPE_TKIP 0x00000004 /* [5212+] */ -#define AR5K_KEYTABLE_TYPE_AES 0x00000005 /* [5211+] */ -#define AR5K_KEYTABLE_TYPE_CCM 0x00000006 /* [5212+] */ -#define AR5K_KEYTABLE_TYPE_NULL 0x00000007 /* [5211+] */ -#define AR5K_KEYTABLE_ANTENNA 0x00000008 /* [5212+] */ -#define AR5K_KEYTABLE_MAC0(_n) AR5K_KEYTABLE_OFF(_n, 6) -#define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7) -#define AR5K_KEYTABLE_VALID 0x00008000 - -/* If key type is TKIP and MIC is enabled - * MIC key goes in offset entry + 64 */ -#define AR5K_KEYTABLE_MIC_OFFSET 64 - -/* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit - * WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit - * WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit - * - * Some vendors have introduced bigger WEP keys to address - * security vulnerabilities in WEP. This includes: - * - * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit - * - * We can expand this if we find ar5k Atheros cards with a larger - * key table size. - */ #define AR5K_KEYTABLE_SIZE_5210 64 #define AR5K_KEYTABLE_SIZE_5211 128 -#define AR5K_KEYTABLE_SIZE (ah->ah_version == AR5K_AR5210 ? \ - AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211) - /*===PHY REGISTERS===*/ @@ -1911,7 +1867,7 @@ #define AR5K_PHY_TURBO 0x9804 /* Register Address */ #define AR5K_PHY_TURBO_MODE 0x00000001 /* Enable turbo mode */ #define AR5K_PHY_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode */ -#define AR5K_PHY_TURBO_MIMO 0x00000004 /* Set turbo for mimo mimo */ +#define AR5K_PHY_TURBO_MIMO 0x00000004 /* Set turbo for mimo */ /* * PHY agility command register diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 307f80e83f94..5b179d01f97d 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -167,7 +167,7 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, * ieee80211_duration() for a brief description of * what rate we should choose to TX ACKs. */ tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw, - sc->vif, 10, rate)); + NULL, 10, rate)); ath5k_hw_reg_write(ah, tx_time, reg); @@ -201,8 +201,6 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) int ret; u32 mask = val ? val : ~0U; - ATH5K_TRACE(ah->ah_sc); - /* Read-and-clear RX Descriptor Pointer*/ ath5k_hw_reg_read(ah, AR5K_RXDP); @@ -246,7 +244,6 @@ static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, unsigned int i; u32 staid, data; - ATH5K_TRACE(ah->ah_sc); staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1); switch (mode) { @@ -329,7 +326,7 @@ commit: * register). After this MAC and Baseband are * disabled and a full reset is needed to come * back. This way we save as much power as possible - * without puting the card on full sleep. + * without putting the card on full sleep. */ int ath5k_hw_on_hold(struct ath5k_hw *ah) { @@ -347,7 +344,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah) /* * Put chipset on warm reset... * - * Note: puting PCI core on warm reset on PCI-E cards + * Note: putting PCI core on warm reset on PCI-E cards * results card to hang and always return 0xffff... so * we ingore that flag for PCI-E cards. On PCI cards * this flag gets cleared after 64 PCI clocks. @@ -393,8 +390,6 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) mode = 0; clock = 0; - ATH5K_TRACE(ah->ah_sc); - /* Wakeup the device */ ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); if (ret) { @@ -405,7 +400,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) /* * Put chipset on warm reset... * - * Note: puting PCI core on warm reset on PCI-E cards + * Note: putting PCI core on warm reset on PCI-E cards * results card to hang and always return 0xffff... so * we ingore that flag for PCI-E cards. On PCI cards * this flag gets cleared after 64 PCI clocks. @@ -734,7 +729,7 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, } static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, - struct ieee80211_channel *channel, u8 *ant, u8 ee_mode) + struct ieee80211_channel *channel, u8 ee_mode) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; s16 cck_ofdm_pwr_delta; @@ -768,17 +763,9 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, ee->ee_cck_ofdm_gain_delta; } - /* Set antenna idle switch table */ - AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL, - AR5K_PHY_ANT_CTL_SWTABLE_IDLE, - (ah->ah_ant_ctl[ee_mode][0] | - AR5K_PHY_ANT_CTL_TXRX_EN)); - - /* Set antenna switch tables */ - ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant[0]], - AR5K_PHY_ANT_SWITCH_TABLE_0); - ath5k_hw_reg_write(ah, ah->ah_ant_ctl[ee_mode][ant[1]], - AR5K_PHY_ANT_SWITCH_TABLE_1); + /* XXX: necessary here? is called from ath5k_hw_set_antenna_mode() + * too */ + ath5k_hw_set_antenna_switch(ah, ee_mode); /* Noise floor threshold */ ath5k_hw_reg_write(ah, @@ -855,7 +842,6 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, AR5K_PHY_NF_THRESH62, ee->ee_thr_62[ee_mode]); - /* False detect backoff for channels * that have spur noise. Write the new * cyclic power RSSI threshold. */ @@ -891,14 +877,11 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel) { struct ath_common *common = ath5k_hw_common(ah); - u32 s_seq[10], s_ant, s_led[3], staid1_flags, tsf_up, tsf_lo; + u32 s_seq[10], s_led[3], staid1_flags, tsf_up, tsf_lo; u32 phy_tst1; - u8 mode, freq, ee_mode, ant[2]; + u8 mode, freq, ee_mode; int i, ret; - ATH5K_TRACE(ah->ah_sc); - - s_ant = 0; ee_mode = 0; staid1_flags = 0; tsf_up = 0; @@ -976,7 +959,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, AR5K_QUEUE_DCU_SEQNUM(0)); } - /* TSF accelerates on AR5211 durring reset + /* TSF accelerates on AR5211 during reset * As a workaround save it here and restore * it later so that it's back in time after * reset. This way it'll get re-synced on the @@ -995,9 +978,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, } } - /* Save default antenna */ - s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); - if (ah->ah_version == AR5K_AR5212) { /* Restore normal 32/40MHz clock operation * to avoid register access delay on certain @@ -1080,7 +1060,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, * XXX: rethink this after new mode changes to * mac80211 are integrated */ if (ah->ah_version == AR5K_AR5212 && - ah->ah_sc->vif != NULL) + ah->ah_sc->nvifs) ath5k_hw_write_rate_duration(ah, mode); /* @@ -1094,22 +1074,17 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* Write OFDM timings on 5212*/ if (ah->ah_version == AR5K_AR5212 && channel->hw_value & CHANNEL_OFDM) { - struct ath5k_eeprom_info *ee = - &ah->ah_capabilities.cap_eeprom; ret = ath5k_hw_write_ofdm_timings(ah, channel); if (ret) return ret; - /* Note: According to docs we can have a newer - * EEPROM on old hardware, so we need to verify - * that our hardware is new enough to have spur - * mitigation registers (delta phase etc) */ - if (ah->ah_mac_srev >= AR5K_SREV_AR5424 || - (ah->ah_mac_srev >= AR5K_SREV_AR5424 && - ee->ee_version >= AR5K_EEPROM_VERSION_5_3)) + /* Spur info is available only from EEPROM versions + * greater than 5.3, but the EEPROM routines will use + * static values for older versions */ + if (ah->ah_mac_srev >= AR5K_SREV_AR5424) ath5k_hw_set_spur_mitigation_filter(ah, - channel); + channel); } /*Enable/disable 802.11b mode on 5111 @@ -1123,21 +1098,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, AR5K_TXCFG_B_MODE); } - /* - * In case a fixed antenna was set as default - * use the same switch table twice. - */ - if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_A) - ant[0] = ant[1] = AR5K_ANT_SWTABLE_A; - else if (ah->ah_ant_mode == AR5K_ANTMODE_FIXED_B) - ant[0] = ant[1] = AR5K_ANT_SWTABLE_B; - else { - ant[0] = AR5K_ANT_SWTABLE_A; - ant[1] = AR5K_ANT_SWTABLE_B; - } - /* Commit values from EEPROM */ - ath5k_hw_commit_eeprom_settings(ah, channel, ant, ee_mode); + ath5k_hw_commit_eeprom_settings(ah, channel, ee_mode); } else { /* @@ -1175,8 +1137,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ath5k_hw_reg_write(ah, tsf_lo, AR5K_TSF_L32); } } - - ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA); } /* Ledstate */ @@ -1200,7 +1160,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, */ /* Restore bssid and bssid mask */ - ath5k_hw_set_associd(ah); + ath5k_hw_set_bssid(ah); /* Set PCU config */ ath5k_hw_set_opmode(ah, op_mode); @@ -1213,11 +1173,11 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* Set RSSI/BRSSI thresholds * * Note: If we decide to set this value - * dynamicaly, have in mind that when AR5K_RSSI_THR - * register is read it might return 0x40 if we haven't - * wrote anything to it plus BMISS RSSI threshold is zeroed. + * dynamically, keep in mind that when AR5K_RSSI_THR + * register is read, it might return 0x40 if we haven't + * written anything to it. Also, BMISS RSSI threshold is zeroed. * So doing a save/restore procedure here isn't the right - * choice. Instead store it on ath5k_hw */ + * choice. Instead, store it in ath5k_hw */ ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES | AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S), @@ -1275,7 +1235,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* * Perform ADC test to see if baseband is ready - * Set tx hold and check adc test register + * Set TX hold and check ADC test register */ phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1); ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1); @@ -1294,15 +1254,15 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, * * This method is used to calibrate some static offsets * used together with on-the fly I/Q calibration (the - * one performed via ath5k_hw_phy_calibrate), that doesn't + * one performed via ath5k_hw_phy_calibrate), which doesn't * interrupt rx path. * * While rx path is re-routed to the power detector we also - * start a noise floor calibration, to measure the + * start a noise floor calibration to measure the * card's noise floor (the noise we measure when we are not - * transmiting or receiving anything). + * transmitting or receiving anything). * - * If we are in a noisy environment AGC calibration may time + * If we are in a noisy environment, AGC calibration may time * out and/or noise floor calibration might timeout. */ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, diff --git a/drivers/net/wireless/ath/ath5k/rfbuffer.h b/drivers/net/wireless/ath/ath5k/rfbuffer.h index e50baff66175..3ac4cff4239d 100644 --- a/drivers/net/wireless/ath/ath5k/rfbuffer.h +++ b/drivers/net/wireless/ath/ath5k/rfbuffer.h @@ -25,10 +25,10 @@ * * We don't write on those registers directly but * we send a data packet on the chip, using a special register, - * that holds all the settings we need. After we 've sent the + * that holds all the settings we need. After we've sent the * data packet, we write on another special register to notify hw * to apply the settings. This is done so that control registers - * can be dynamicaly programmed during operation and the settings + * can be dynamically programmed during operation and the settings * are applied faster on the hw. * * We call each data packet an "RF Bank" and all the data we write diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c new file mode 100644 index 000000000000..90757de7bf59 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/sysfs.c @@ -0,0 +1,116 @@ +#include <linux/device.h> +#include <linux/pci.h> + +#include "base.h" +#include "ath5k.h" +#include "reg.h" + +#define SIMPLE_SHOW_STORE(name, get, set) \ +static ssize_t ath5k_attr_show_##name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct ath5k_softc *sc = dev_get_drvdata(dev); \ + return snprintf(buf, PAGE_SIZE, "%d\n", get); \ +} \ + \ +static ssize_t ath5k_attr_store_##name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct ath5k_softc *sc = dev_get_drvdata(dev); \ + int val; \ + \ + val = (int)simple_strtoul(buf, NULL, 10); \ + set(sc->ah, val); \ + return count; \ +} \ +static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, \ + ath5k_attr_show_##name, ath5k_attr_store_##name) + +#define SIMPLE_SHOW(name, get) \ +static ssize_t ath5k_attr_show_##name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct ath5k_softc *sc = dev_get_drvdata(dev); \ + return snprintf(buf, PAGE_SIZE, "%d\n", get); \ +} \ +static DEVICE_ATTR(name, S_IRUGO, ath5k_attr_show_##name, NULL) + +/*** ANI ***/ + +SIMPLE_SHOW_STORE(ani_mode, sc->ani_state.ani_mode, ath5k_ani_init); +SIMPLE_SHOW_STORE(noise_immunity_level, sc->ani_state.noise_imm_level, + ath5k_ani_set_noise_immunity_level); +SIMPLE_SHOW_STORE(spur_level, sc->ani_state.spur_level, + ath5k_ani_set_spur_immunity_level); +SIMPLE_SHOW_STORE(firstep_level, sc->ani_state.firstep_level, + ath5k_ani_set_firstep_level); +SIMPLE_SHOW_STORE(ofdm_weak_signal_detection, sc->ani_state.ofdm_weak_sig, + ath5k_ani_set_ofdm_weak_signal_detection); +SIMPLE_SHOW_STORE(cck_weak_signal_detection, sc->ani_state.cck_weak_sig, + ath5k_ani_set_cck_weak_signal_detection); +SIMPLE_SHOW(spur_level_max, sc->ani_state.max_spur_level); + +static ssize_t ath5k_attr_show_noise_immunity_level_max(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ATH5K_ANI_MAX_NOISE_IMM_LVL); +} +static DEVICE_ATTR(noise_immunity_level_max, S_IRUGO, + ath5k_attr_show_noise_immunity_level_max, NULL); + +static ssize_t ath5k_attr_show_firstep_level_max(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ATH5K_ANI_MAX_FIRSTEP_LVL); +} +static DEVICE_ATTR(firstep_level_max, S_IRUGO, + ath5k_attr_show_firstep_level_max, NULL); + +static struct attribute *ath5k_sysfs_entries_ani[] = { + &dev_attr_ani_mode.attr, + &dev_attr_noise_immunity_level.attr, + &dev_attr_spur_level.attr, + &dev_attr_firstep_level.attr, + &dev_attr_ofdm_weak_signal_detection.attr, + &dev_attr_cck_weak_signal_detection.attr, + &dev_attr_noise_immunity_level_max.attr, + &dev_attr_spur_level_max.attr, + &dev_attr_firstep_level_max.attr, + NULL +}; + +static struct attribute_group ath5k_attribute_group_ani = { + .name = "ani", + .attrs = ath5k_sysfs_entries_ani, +}; + + +/*** register / unregister ***/ + +int +ath5k_sysfs_register(struct ath5k_softc *sc) +{ + struct device *dev = &sc->pdev->dev; + int err; + + err = sysfs_create_group(&dev->kobj, &ath5k_attribute_group_ani); + if (err) { + ATH5K_ERR(sc, "failed to create sysfs group\n"); + return err; + } + + return 0; +} + +void +ath5k_sysfs_unregister(struct ath5k_softc *sc) +{ + struct device *dev = &sc->pdev->dev; + + sysfs_remove_group(&dev->kobj, &ath5k_attribute_group_ani); +} |