diff options
author | Felix Fietkau <nbd@openwrt.org> | 2010-10-09 00:36:54 +0000 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2010-10-09 00:36:54 +0000 |
commit | e3bb3bcd97ec4f07a2c77dd15c50546ab433651b (patch) | |
tree | 45ac651452b19d2a2c71210fe9c0c254f9db28e5 /package/mac80211/patches/522-ath_common_counters.patch | |
parent | 74f46e5ac2c85a8990b4b44ccd870812b1f4efff (diff) | |
download | master-187ad058-e3bb3bcd97ec4f07a2c77dd15c50546ab433651b.tar.gz master-187ad058-e3bb3bcd97ec4f07a2c77dd15c50546ab433651b.tar.bz2 master-187ad058-e3bb3bcd97ec4f07a2c77dd15c50546ab433651b.zip |
ath9k: implement extended channel utilization statistics via survey
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@23350 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/mac80211/patches/522-ath_common_counters.patch')
-rw-r--r-- | package/mac80211/patches/522-ath_common_counters.patch | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/package/mac80211/patches/522-ath_common_counters.patch b/package/mac80211/patches/522-ath_common_counters.patch new file mode 100644 index 0000000000..f719575264 --- /dev/null +++ b/package/mac80211/patches/522-ath_common_counters.patch @@ -0,0 +1,347 @@ +--- a/drivers/net/wireless/ath/ath.h ++++ b/drivers/net/wireless/ath/ath.h +@@ -19,6 +19,7 @@ + + #include <linux/skbuff.h> + #include <linux/if_ether.h> ++#include <linux/spinlock.h> + #include <net/mac80211.h> + + /* +@@ -42,6 +43,13 @@ struct ath_ani { + struct timer_list timer; + }; + ++struct ath_cycle_counters { ++ u32 cycles; ++ u32 rx_busy; ++ u32 rx_frame; ++ u32 tx_frame; ++}; ++ + enum ath_device_state { + ATH_HW_UNAVAILABLE, + ATH_HW_INITIALIZED, +@@ -147,6 +155,10 @@ struct ath_common { + + unsigned int clockrate; + ++ spinlock_t cc_lock; ++ struct ath_cycle_counters cc_ani; ++ struct ath_cycle_counters cc_survey; ++ + struct ath_regulatory regulatory; + const struct ath_ops *ops; + const struct ath_bus_ops *bus_ops; +@@ -163,5 +175,7 @@ int ath_key_config(struct ath_common *co + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); + bool ath_hw_keyreset(struct ath_common *common, u16 entry); ++void ath_hw_cycle_counters_update(struct ath_common *common); ++int32_t ath_hw_get_listen_time(struct ath_common *common); + + #endif /* ATH_H */ +--- a/drivers/net/wireless/ath/ath9k/ani.c ++++ b/drivers/net/wireless/ath/ath9k/ani.c +@@ -465,18 +465,6 @@ static void ath9k_hw_ani_lower_immunity( + ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1); + } + +-static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) +-{ +- struct ath_common *common = ath9k_hw_common(ah); +- int32_t listen_time; +- +- ath9k_hw_update_cycle_counters(ah); +- listen_time = ah->listen_time / (common->clockrate * 1000); +- ah->listen_time = 0; +- +- return listen_time; +-} +- + static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) + { + struct ar5416AniState *aniState; +@@ -655,7 +643,9 @@ static void ath9k_hw_ani_read_counters(s + u32 phyCnt1, phyCnt2; + int32_t listenTime; + +- listenTime = ath9k_hw_ani_get_listen_time(ah); ++ ath_hw_cycle_counters_update(common); ++ listenTime = ath_hw_get_listen_time(common); ++ + if (listenTime < 0) { + ah->stats.ast_ani_lneg++; + ath9k_ani_restart(ah); +@@ -796,54 +786,6 @@ void ath9k_hw_disable_mib_counters(struc + } + EXPORT_SYMBOL(ath9k_hw_disable_mib_counters); + +-void ath9k_hw_update_cycle_counters(struct ath_hw *ah) +-{ +- struct ath_cycle_counters cc; +- bool clear; +- +- memcpy(&cc, &ah->cc, sizeof(cc)); +- +- /* freeze counters */ +- REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); +- +- ah->cc.cycles = REG_READ(ah, AR_CCCNT); +- if (ah->cc.cycles < cc.cycles) { +- clear = true; +- goto skip; +- } +- +- ah->cc.rx_clear = REG_READ(ah, AR_RCCNT); +- ah->cc.rx_frame = REG_READ(ah, AR_RFCNT); +- ah->cc.tx_frame = REG_READ(ah, AR_TFCNT); +- +- /* prevent wraparound */ +- if (ah->cc.cycles & BIT(31)) +- clear = true; +- +-#define CC_DELTA(_field, _reg) ah->cc_delta._field += ah->cc._field - cc._field +- CC_DELTA(cycles, AR_CCCNT); +- CC_DELTA(rx_frame, AR_RFCNT); +- CC_DELTA(rx_clear, AR_RCCNT); +- CC_DELTA(tx_frame, AR_TFCNT); +-#undef CC_DELTA +- +- ah->listen_time += (ah->cc.cycles - cc.cycles) - +- ((ah->cc.rx_frame - cc.rx_frame) + +- (ah->cc.tx_frame - cc.tx_frame)); +- +-skip: +- if (clear) { +- REG_WRITE(ah, AR_CCCNT, 0); +- REG_WRITE(ah, AR_RFCNT, 0); +- REG_WRITE(ah, AR_RCCNT, 0); +- REG_WRITE(ah, AR_TFCNT, 0); +- memset(&ah->cc, 0, sizeof(ah->cc)); +- } +- +- /* unfreeze counters */ +- REG_WRITE(ah, AR_MIBC, 0); +-} +- + /* + * Process a MIB interrupt. We may potentially be invoked because + * any of the MIB counters overflow/trigger so don't assume we're +--- a/drivers/net/wireless/ath/ath9k/ani.h ++++ b/drivers/net/wireless/ath/ath9k/ani.h +@@ -93,13 +93,6 @@ struct ath9k_mib_stats { + u32 beacons; + }; + +-struct ath_cycle_counters { +- u32 cycles; +- u32 rx_frame; +- u32 rx_clear; +- u32 tx_frame; +-}; +- + /* INI default values for ANI registers */ + struct ath9k_ani_default { + u16 m1ThreshLow; +@@ -164,7 +157,6 @@ struct ar5416Stats { + + void ath9k_enable_mib_counters(struct ath_hw *ah); + void ath9k_hw_disable_mib_counters(struct ath_hw *ah); +-void ath9k_hw_update_cycle_counters(struct ath_hw *ah); + void ath9k_hw_ani_setup(struct ath_hw *ah); + void ath9k_hw_ani_init(struct ath_hw *ah); + int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, +--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c +@@ -1254,13 +1254,12 @@ void ar9003_hw_bb_watchdog_dbg_info(stru + "** BB mode: BB_gen_controls=0x%08x **\n", + REG_READ(ah, AR_PHY_GEN_CTRL)); + +- ath9k_hw_update_cycle_counters(ah); +-#define PCT(_field) (ah->cc_delta._field * 100 / ah->cc_delta.cycles) +- if (ah->cc_delta.cycles) ++#define PCT(_field) (common->cc_survey._field * 100 / common->cc_survey.cycles) ++ if (common->cc_survey.cycles) + ath_print(common, ATH_DBG_RESET, + "** BB busy times: rx_clear=%d%%, " + "rx_frame=%d%%, tx_frame=%d%% **\n", +- PCT(rx_clear), PCT(rx_frame), PCT(tx_frame)); ++ PCT(rx_busy), PCT(rx_frame), PCT(tx_frame)); + + ath_print(common, ATH_DBG_RESET, + "==== BB update: done ====\n\n"); +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -740,8 +740,6 @@ struct ath_hw { + int coarse_low[5]; + int firpwr[5]; + enum ath9k_ani_cmd ani_function; +- struct ath_cycle_counters cc, cc_delta; +- int32_t listen_time; + + /* Bluetooth coexistance */ + struct ath_btcoex_hw btcoex_hw; +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -400,6 +400,7 @@ void ath_ani_calibrate(unsigned long dat + bool aniflag = false; + unsigned int timestamp = jiffies_to_msecs(jiffies); + u32 cal_interval, short_cal_interval, long_cal_interval; ++ unsigned long flags; + + if (ah->caldata && ah->caldata->nfcal_interference) + long_cal_interval = ATH_LONG_CALINTERVAL_INT; +@@ -450,8 +451,11 @@ void ath_ani_calibrate(unsigned long dat + /* Skip all processing if there's nothing to do. */ + if (longcal || shortcal || aniflag) { + /* Call ANI routine if necessary */ +- if (aniflag) ++ if (aniflag) { ++ spin_lock_irqsave(&common->cc_lock, flags); + ath9k_hw_ani_monitor(ah, ah->curchan); ++ spin_unlock_irqrestore(&common->cc_lock, flags); ++ } + + /* Perform calibration if necessary */ + if (longcal || shortcal) { +@@ -636,6 +640,7 @@ irqreturn_t ath_isr(int irq, void *dev) + + struct ath_softc *sc = dev; + struct ath_hw *ah = sc->sc_ah; ++ struct ath_common *common = ath9k_hw_common(ah); + enum ath9k_int status; + bool sched = false; + +@@ -685,7 +690,12 @@ irqreturn_t ath_isr(int irq, void *dev) + + if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && + (status & ATH9K_INT_BB_WATCHDOG)) { ++ ++ spin_lock(&common->cc_lock); ++ ath_hw_cycle_counters_update(common); + ar9003_hw_bb_watchdog_dbg_info(ah); ++ spin_unlock(&common->cc_lock); ++ + goto chip_reset; + } + +--- a/drivers/net/wireless/ath/ath9k/reg.h ++++ b/drivers/net/wireless/ath/ath9k/reg.h +@@ -107,12 +107,6 @@ + #define AR_RXCFG_DMASZ_256B 6 + #define AR_RXCFG_DMASZ_512B 7 + +-#define AR_MIBC 0x0040 +-#define AR_MIBC_COW 0x00000001 +-#define AR_MIBC_FMC 0x00000002 +-#define AR_MIBC_CMC 0x00000004 +-#define AR_MIBC_MCS 0x00000008 +- + #define AR_TOPS 0x0044 + #define AR_TOPS_MASK 0x0000FFFF + +@@ -1524,11 +1518,6 @@ enum { + #define AR_TPC_CHIRP 0x003f0000 + #define AR_TPC_CHIRP_S 0x16 + +-#define AR_TFCNT 0x80ec +-#define AR_RFCNT 0x80f0 +-#define AR_RCCNT 0x80f4 +-#define AR_CCCNT 0x80f8 +- + #define AR_QUIET1 0x80fc + #define AR_QUIET1_NEXT_QUIET_S 0 + #define AR_QUIET1_NEXT_QUIET_M 0x0000ffff +--- a/drivers/net/wireless/ath/hw.c ++++ b/drivers/net/wireless/ath/hw.c +@@ -124,3 +124,62 @@ void ath_hw_setbssidmask(struct ath_comm + REG_WRITE(ah, get_unaligned_le16(common->bssidmask + 4), AR_BSSMSKU); + } + EXPORT_SYMBOL(ath_hw_setbssidmask); ++ ++ ++/** ++ * ath_hw_cycle_counters_update - common function to update cycle counters ++ * ++ * @common: the ath_common struct for the device. ++ * ++ * This function is used to update all cycle counters in one place. ++ * It has to be called while holding common->cc_lock! ++ */ ++void ath_hw_cycle_counters_update(struct ath_common *common) ++{ ++ u32 cycles, busy, rx, tx; ++ void *ah = common->ah; ++ ++ /* freeze */ ++ REG_WRITE(ah, AR_MIBC_FMC, AR_MIBC); ++ ++ /* read */ ++ cycles = REG_READ(ah, AR_CCCNT); ++ busy = REG_READ(ah, AR_RCCNT); ++ rx = REG_READ(ah, AR_RFCNT); ++ tx = REG_READ(ah, AR_TFCNT); ++ ++ /* clear */ ++ REG_WRITE(ah, 0, AR_CCCNT); ++ REG_WRITE(ah, 0, AR_RFCNT); ++ REG_WRITE(ah, 0, AR_RCCNT); ++ REG_WRITE(ah, 0, AR_TFCNT); ++ ++ /* unfreeze */ ++ REG_WRITE(ah, 0, AR_MIBC); ++ ++ /* update all cycle counters here */ ++ common->cc_ani.cycles += cycles; ++ common->cc_ani.rx_busy += busy; ++ common->cc_ani.rx_frame += rx; ++ common->cc_ani.tx_frame += tx; ++ ++ common->cc_survey.cycles += cycles; ++ common->cc_survey.rx_busy += busy; ++ common->cc_survey.rx_frame += rx; ++ common->cc_survey.tx_frame += tx; ++} ++EXPORT_SYMBOL(ath_hw_cycle_counters_update); ++ ++int32_t ath_hw_get_listen_time(struct ath_common *common) ++{ ++ struct ath_cycle_counters *cc = &common->cc_ani; ++ int32_t listen_time; ++ ++ listen_time = (cc->cycles - cc->rx_frame - cc->tx_frame) / ++ (common->clockrate * 1000); ++ ++ memset(cc, 0, sizeof(*cc)); ++ ++ return listen_time; ++} ++EXPORT_SYMBOL(ath_hw_get_listen_time); +--- a/drivers/net/wireless/ath/reg.h ++++ b/drivers/net/wireless/ath/reg.h +@@ -17,6 +17,12 @@ + #ifndef ATH_REGISTERS_H + #define ATH_REGISTERS_H + ++#define AR_MIBC 0x0040 ++#define AR_MIBC_COW 0x00000001 ++#define AR_MIBC_FMC 0x00000002 ++#define AR_MIBC_CMC 0x00000004 ++#define AR_MIBC_MCS 0x00000008 ++ + /* + * BSSID mask registers. See ath_hw_set_bssid_mask() + * for detailed documentation about these registers. +@@ -24,6 +30,11 @@ + #define AR_BSSMSKL 0x80e0 + #define AR_BSSMSKU 0x80e4 + ++#define AR_TFCNT 0x80ec ++#define AR_RFCNT 0x80f0 ++#define AR_RCCNT 0x80f4 ++#define AR_CCCNT 0x80f8 ++ + #define AR_KEYTABLE_0 0x8800 + #define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32)) + #define AR_KEY_CACHE_SIZE 128 |