This change updates ath5k to do ANI adjustments every 100 ms using the common ANI code in the ath module.
Signed-off-by: Bob Copeland <m...@bobcopeland.com> --- drivers/net/wireless/ath/ani.c | 6 +++ drivers/net/wireless/ath/ath5k/ath5k.h | 4 ++ drivers/net/wireless/ath/ath5k/attach.c | 7 +++ drivers/net/wireless/ath/ath5k/base.c | 69 +++++++++++++++++-------------- drivers/net/wireless/ath/ath5k/pcu.c | 24 +++++++++- drivers/net/wireless/ath/ath5k/phy.c | 24 ++++++++-- 6 files changed, 95 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/ath/ani.c b/drivers/net/wireless/ath/ani.c index c2a09fe..b9fb64e 100644 --- a/drivers/net/wireless/ath/ani.c +++ b/drivers/net/wireless/ath/ani.c @@ -107,6 +107,7 @@ static bool ath_hw_ani_control(struct ath_common *common, m2CountThrLow[on]); /* FIXME not ath5k? */ +#if 0 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]); @@ -119,6 +120,7 @@ static bool ath_hw_ani_control(struct ath_common *common, REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]); +#endif if (on) REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, @@ -727,8 +729,12 @@ void ath_hw_procmibevent(struct ath_common *common) /* Reset these counters regardless */ REG_WRITE(ah, AR_FILT_OFDM, 0); REG_WRITE(ah, AR_FILT_CCK, 0); + + /* FIXME not ath5k? */ +#if 0 if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); +#endif /* Clear the mib counters and save them in the stats */ ath_hw_update_mibstats(common, &common->mib_stats); diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 6a2a967..1da3875 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -203,6 +203,8 @@ #define AR5K_TUNE_DEFAULT_TXPOWER 25 #define AR5K_TUNE_TPC_TXPOWER false #define AR5K_TUNE_HWTXTRIES 4 +/* ANI poll interval in ms */ +#define AR5K_TUNE_ANI_POLL_INTERVAL 100 #define AR5K_INIT_CARR_SENSE_EN 1 @@ -917,6 +919,7 @@ enum ath5k_int { enum ath5k_software_interrupt { AR5K_SWI_FULL_CALIBRATION = 0x01, AR5K_SWI_SHORT_CALIBRATION = 0x02, + AR5K_SWI_ANI_CALIBRATION = 0x03, }; /* @@ -1213,6 +1216,7 @@ extern int ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index); extern int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index); extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah); extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter); +extern void ath5k_hw_set_rx_filter_phy_err(void *hw, bool enable); /* Beacon control functions */ extern u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah); extern u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 4228444..6b4071e 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -25,6 +25,7 @@ #include "reg.h" #include "debug.h" #include "base.h" +#include "../ani.h" /** * ath5k_hw_post - Power On Self Test helper function @@ -336,6 +337,10 @@ int ath5k_hw_attach(struct ath5k_softc *sc) /* turn on HW LEDs */ ath5k_hw_set_ledstate(ah, AR5K_LED_INIT); + common->ani.ani_function = ATH_ANI_ALL; + ath_hw_ani_setup(common); + ath_hw_ani_init(common); + return 0; err_free: kfree(ah); @@ -351,6 +356,8 @@ void ath5k_hw_detach(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); + ath_hw_ani_disable(ath5k_hw_common(ah)); + __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 8446863..e40757b 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -58,8 +58,9 @@ #include "base.h" #include "reg.h" #include "debug.h" +#include "../ani.h" -static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ +static u8 ath5k_calinterval = 30; /* Calibrate PHY every 30 secs */ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); @@ -455,6 +456,7 @@ static void ath5k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) static const struct ath_ops ath5k_common_ops = { .read = ath5k_ioread32, .write = ath5k_iowrite32, + .setrxfilter_phy_err = ath5k_hw_set_rx_filter_phy_err, }; static int __devinit @@ -600,6 +602,12 @@ ath5k_pci_probe(struct pci_dev *pdev, common->hw = hw; common->cachelsz = csz << 2; /* convert to bytes */ + /* initial default for ANI */ + common->ani.noise_floor = -95; + + printk(KERN_DEBUG "ath5k: about to attach (ops: %p)\n", + common->ops); + /* Initialize device */ ret = ath5k_hw_attach(sc); if (ret) { @@ -2381,6 +2389,9 @@ ath5k_init(struct ath5k_softc *sc) */ ath5k_stop_locked(sc); + /* Set PHY calibration inteval */ + ah->ah_cal_intval = ath5k_calinterval; + /* * The basic interface to setting the hardware in a good * state is ``reset''. On return the hardware is known to @@ -2392,7 +2403,8 @@ ath5k_init(struct ath5k_softc *sc) sc->curband = &sc->sbands[sc->curchan->band]; sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | - AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI; + AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI | + AR5K_INT_MIB; ret = ath5k_reset(sc, NULL); if (ret) goto done; @@ -2409,9 +2421,6 @@ ath5k_init(struct ath5k_softc *sc) /* Set ack to be sent at low bit-rates */ ath5k_hw_set_ack_bitrate_high(ah, false); - /* Set PHY calibration inteval */ - ah->ah_cal_intval = ath5k_calinterval; - ret = 0; done: mmiowb(); @@ -2566,11 +2575,7 @@ ath5k_intr(int irq, void *dev_id) tasklet_schedule(&sc->calib); } if (status & AR5K_INT_MIB) { - /* - * These stats are also used for ANI i think - * so how about updating them more often ? - */ - ath5k_hw_update_mib_counters(ah, &sc->ll_stats); + ath_hw_procmibevent(ath5k_hw_common(ah)); } if (status & AR5K_INT_GPIO) tasklet_schedule(&sc->rf_kill.toggleq); @@ -2604,36 +2609,38 @@ ath5k_tasklet_calibrate(unsigned long data) struct ath5k_softc *sc = (void *)data; struct ath5k_hw *ah = sc->ah; - /* Only full calibration for now */ - if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION) + /* Check for ani/full calibration */ + if (!(ah->ah_swi_mask & + (AR5K_SWI_ANI_CALIBRATION | AR5K_SWI_FULL_CALIBRATION))) return; - /* 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); + if (ah->ah_swi_mask & AR5K_SWI_ANI_CALIBRATION) + ath_hw_ani_monitor(ath5k_hw_common(ah)); - if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) { - /* - * Rfgain is out of bounds, reset the chip - * to load new gain values. - */ - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); - ath5k_reset_wake(sc); - } - if (ath5k_hw_phy_calibrate(ah, sc->curchan)) - ATH5K_ERR(sc, "calibration of channel %u failed\n", + if (ah->ah_swi_mask & AR5K_SWI_FULL_CALIBRATION) { + ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", ieee80211_frequency_to_channel( - sc->curchan->center_freq)); + sc->curchan->center_freq), + sc->curchan->hw_value); + if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) { + /* + * Rfgain is out of bounds, reset the chip + * to load new gain values. + */ + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, + "calibration, resetting\n"); + ath5k_reset_wake(sc); + } + if (ath5k_hw_phy_calibrate(ah, sc->curchan)) + ATH5K_ERR(sc, "calibration of channel %u failed\n", + ieee80211_frequency_to_channel( + sc->curchan->center_freq)); + } ah->ah_swi_mask = 0; /* Wake queues */ ieee80211_wake_queues(sc->hw); - } diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 64fc1eb..4d26c7a 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -30,6 +30,7 @@ #include "reg.h" #include "debug.h" #include "base.h" +#include "../ani.h" /*******************\ * Generic functions * @@ -337,11 +338,16 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) * (ACK etc). * * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma - * TODO: Init ANI here */ void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) { + struct ath_common *common = ath5k_hw_common(ah); + ATH5K_TRACE(ah->ah_sc); + + ath_enable_mib_counters(common); + ath_ani_reset(common, ah->ah_current_channel); + AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); } @@ -352,11 +358,11 @@ void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) * * Stops RX engine on PCU * - * TODO: Detach ANI here */ void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah) { ATH5K_TRACE(ah->ah_sc); + ath_hw_disable_mib_counters(ath5k_hw_common(ah)); AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); } @@ -483,9 +489,21 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) /*Write PHY error filter register on 5212*/ if (ah->ah_version == AR5K_AR5212) ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL); - } +EXPORT_SYMBOL(ath5k_hw_set_rx_filter_phy_err); +void ath5k_hw_set_rx_filter_phy_err(void *hw, bool enable) +{ + struct ath5k_hw *ah = hw; + + u32 filt = ath5k_hw_get_rx_filter(ah); + if (enable) + filt |= AR5K_RX_FILTER_PHYERR; + else + filt &= ~AR5K_RX_FILTER_PHYERR; + + ath5k_hw_set_rx_filter(ah, filt); +} /****************\ * Beacon control * diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 72474c0..d6be62a 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1107,23 +1107,37 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) void ath5k_hw_calibration_poll(struct ath5k_hw *ah) { + struct ath_common *common = ath5k_hw_common(ah); + /* Calibration interval in jiffies */ - unsigned long cal_intval; + unsigned long cal_intval, ani_intval; cal_intval = msecs_to_jiffies(ah->ah_cal_intval * 1000); + ani_intval = msecs_to_jiffies(AR5K_TUNE_ANI_POLL_INTERVAL); - /* Initialize timestamp if needed */ - if (!ah->ah_cal_tstamp) + /* Initialize timestamps if needed */ + if (!ah->ah_cal_tstamp || !common->ani.checkani_timer) { ah->ah_cal_tstamp = jiffies; + common->ani.checkani_timer = jiffies; + } + + /* do ani if past ANI calibration window */ + if (time_is_before_eq_jiffies(common->ani.checkani_timer + + ani_intval)) { + common->ani.checkani_timer = jiffies; + ah->ah_swi_mask |= AR5K_SWI_ANI_CALIBRATION; + } /* For now we always do full calibration * Mark software interrupt mask and fire software * interrupt (bit gets auto-cleared) */ if (time_is_before_eq_jiffies(ah->ah_cal_tstamp + cal_intval)) { ah->ah_cal_tstamp = jiffies; - ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION; - AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); + ah->ah_swi_mask |= AR5K_SWI_FULL_CALIBRATION; } + + /* fire software interrupt (bit gets auto-cleared) */ + AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); } static int sign_extend(int val, const int nbits) -- 1.6.3.3 _______________________________________________ ath5k-devel mailing list ath5k-devel@lists.ath5k.org https://lists.ath5k.org/mailman/listinfo/ath5k-devel