aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/ani.c
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2010-10-03 19:07:17 +0200
committerJohn W. Linville <linville@tuxdriver.com>2010-10-06 16:26:01 -0400
commit9dbebc7fd07ab66341dce8d001272db400c11e03 (patch)
tree492fd72be595cb7f397d83b2cd4a567cbec73cb4 /drivers/net/wireless/ath/ath9k/ani.c
parent6497827f53eb90dcf30c5d6414c83238f722e8ae (diff)
downloadkernel_samsung_smdk4412-9dbebc7fd07ab66341dce8d001272db400c11e03.zip
kernel_samsung_smdk4412-9dbebc7fd07ab66341dce8d001272db400c11e03.tar.gz
kernel_samsung_smdk4412-9dbebc7fd07ab66341dce8d001272db400c11e03.tar.bz2
ath9k_hw: merge codepaths that access the cycle counter registers
The cycle counters are used by ANI to determine the amount of time that the radio spent not receiving or transmitting. They're also used for debugging purposes if the baseband watchdog on AR9003 detects a lockup. In the future, we want to use these counters to determine the medium utilization and export this information via survey. For that, we need to make sure that the counter is only accessed from one place, which also ensures that wraparounds won't occur at inconvenient points in time. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/ani.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c119
1 files changed, 47 insertions, 72 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index 45f477a..3fba81e 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -549,47 +549,15 @@ static u8 ath9k_hw_chan_2_clockrate_mhz(struct ath_hw *ah)
static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
{
- struct ar5416AniState *aniState;
- struct ath_common *common = ath9k_hw_common(ah);
- u32 txFrameCount, rxFrameCount, cycleCount;
- int32_t listenTime;
-
- txFrameCount = REG_READ(ah, AR_TFCNT);
- rxFrameCount = REG_READ(ah, AR_RFCNT);
- cycleCount = REG_READ(ah, AR_CCCNT);
-
- aniState = ah->curani;
- if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
- listenTime = 0;
- ah->stats.ast_ani_lzero++;
- ath_print(common, ATH_DBG_ANI,
- "1st call: aniState->cycleCount=%d\n",
- aniState->cycleCount);
- } else {
- int32_t ccdelta = cycleCount - aniState->cycleCount;
- int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
- int32_t tfdelta = txFrameCount - aniState->txFrameCount;
- int32_t clock_rate;
-
- /*
- * convert HW counter values to ms using mode
- * specifix clock rate
- */
- clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;;
+ int32_t listen_time;
+ int32_t clock_rate;
- listenTime = (ccdelta - rfdelta - tfdelta) / clock_rate;
+ ath9k_hw_update_cycle_counters(ah);
+ clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;
+ listen_time = ah->listen_time / clock_rate;
+ ah->listen_time = 0;
- ath_print(common, ATH_DBG_ANI,
- "cyclecount=%d, rfcount=%d, "
- "tfcount=%d, listenTime=%d CLOCK_RATE=%d\n",
- ccdelta, rfdelta, tfdelta, listenTime, clock_rate);
- }
-
- aniState->cycleCount = cycleCount;
- aniState->txFrameCount = txFrameCount;
- aniState->rxFrameCount = rxFrameCount;
-
- return listenTime;
+ return listen_time;
}
static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
@@ -1041,45 +1009,52 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
}
EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
- u32 *rxc_pcnt,
- u32 *rxf_pcnt,
- u32 *txf_pcnt)
+void ath9k_hw_update_cycle_counters(struct ath_hw *ah)
{
- struct ath_common *common = ath9k_hw_common(ah);
- static u32 cycles, rx_clear, rx_frame, tx_frame;
- u32 good = 1;
+ struct ath_cycle_counters cc;
+ bool clear;
- u32 rc = REG_READ(ah, AR_RCCNT);
- u32 rf = REG_READ(ah, AR_RFCNT);
- u32 tf = REG_READ(ah, AR_TFCNT);
- u32 cc = REG_READ(ah, AR_CCCNT);
+ memcpy(&cc, &ah->cc, sizeof(cc));
- if (cycles == 0 || cycles > cc) {
- ath_print(common, ATH_DBG_ANI,
- "cycle counter wrap. ExtBusy = 0\n");
- good = 0;
- } else {
- u32 cc_d = cc - cycles;
- u32 rc_d = rc - rx_clear;
- u32 rf_d = rf - rx_frame;
- u32 tf_d = tf - tx_frame;
-
- if (cc_d != 0) {
- *rxc_pcnt = rc_d * 100 / cc_d;
- *rxf_pcnt = rf_d * 100 / cc_d;
- *txf_pcnt = tf_d * 100 / cc_d;
- } else {
- good = 0;
- }
+ /* 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;
}
- cycles = cc;
- rx_frame = rf;
- rx_clear = rc;
- tx_frame = tf;
+ 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));
+ }
- return good;
+ /* unfreeze counters */
+ REG_WRITE(ah, AR_MIBC, 0);
}
/*