aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2010-10-03 13:07:17 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-10-06 16:26:01 -0400
commit9dbebc7fd07ab66341dce8d001272db400c11e03 (patch)
tree492fd72be595cb7f397d83b2cd4a567cbec73cb4
parent6497827f53eb90dcf30c5d6414c83238f722e8ae (diff)
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>
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c119
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.h13
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h2
5 files changed, 65 insertions, 92 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index 45f477ad7608..3fba81e3a61f 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)
549 549
550static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) 550static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
551{ 551{
552 struct ar5416AniState *aniState; 552 int32_t listen_time;
553 struct ath_common *common = ath9k_hw_common(ah); 553 int32_t clock_rate;
554 u32 txFrameCount, rxFrameCount, cycleCount;
555 int32_t listenTime;
556
557 txFrameCount = REG_READ(ah, AR_TFCNT);
558 rxFrameCount = REG_READ(ah, AR_RFCNT);
559 cycleCount = REG_READ(ah, AR_CCCNT);
560
561 aniState = ah->curani;
562 if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
563 listenTime = 0;
564 ah->stats.ast_ani_lzero++;
565 ath_print(common, ATH_DBG_ANI,
566 "1st call: aniState->cycleCount=%d\n",
567 aniState->cycleCount);
568 } else {
569 int32_t ccdelta = cycleCount - aniState->cycleCount;
570 int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
571 int32_t tfdelta = txFrameCount - aniState->txFrameCount;
572 int32_t clock_rate;
573
574 /*
575 * convert HW counter values to ms using mode
576 * specifix clock rate
577 */
578 clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;;
579 554
580 listenTime = (ccdelta - rfdelta - tfdelta) / clock_rate; 555 ath9k_hw_update_cycle_counters(ah);
556 clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;
557 listen_time = ah->listen_time / clock_rate;
558 ah->listen_time = 0;
581 559
582 ath_print(common, ATH_DBG_ANI, 560 return listen_time;
583 "cyclecount=%d, rfcount=%d, "
584 "tfcount=%d, listenTime=%d CLOCK_RATE=%d\n",
585 ccdelta, rfdelta, tfdelta, listenTime, clock_rate);
586 }
587
588 aniState->cycleCount = cycleCount;
589 aniState->txFrameCount = txFrameCount;
590 aniState->rxFrameCount = rxFrameCount;
591
592 return listenTime;
593} 561}
594 562
595static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) 563static 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)
1041} 1009}
1042EXPORT_SYMBOL(ath9k_hw_disable_mib_counters); 1010EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
1043 1011
1044u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, 1012void ath9k_hw_update_cycle_counters(struct ath_hw *ah)
1045 u32 *rxc_pcnt,
1046 u32 *rxf_pcnt,
1047 u32 *txf_pcnt)
1048{ 1013{
1049 struct ath_common *common = ath9k_hw_common(ah); 1014 struct ath_cycle_counters cc;
1050 static u32 cycles, rx_clear, rx_frame, tx_frame; 1015 bool clear;
1051 u32 good = 1;
1052 1016
1053 u32 rc = REG_READ(ah, AR_RCCNT); 1017 memcpy(&cc, &ah->cc, sizeof(cc));
1054 u32 rf = REG_READ(ah, AR_RFCNT);
1055 u32 tf = REG_READ(ah, AR_TFCNT);
1056 u32 cc = REG_READ(ah, AR_CCCNT);
1057 1018
1058 if (cycles == 0 || cycles > cc) { 1019 /* freeze counters */
1059 ath_print(common, ATH_DBG_ANI, 1020 REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
1060 "cycle counter wrap. ExtBusy = 0\n"); 1021
1061 good = 0; 1022 ah->cc.cycles = REG_READ(ah, AR_CCCNT);
1062 } else { 1023 if (ah->cc.cycles < cc.cycles) {
1063 u32 cc_d = cc - cycles; 1024 clear = true;
1064 u32 rc_d = rc - rx_clear; 1025 goto skip;
1065 u32 rf_d = rf - rx_frame;
1066 u32 tf_d = tf - tx_frame;
1067
1068 if (cc_d != 0) {
1069 *rxc_pcnt = rc_d * 100 / cc_d;
1070 *rxf_pcnt = rf_d * 100 / cc_d;
1071 *txf_pcnt = tf_d * 100 / cc_d;
1072 } else {
1073 good = 0;
1074 }
1075 } 1026 }
1076 1027
1077 cycles = cc; 1028 ah->cc.rx_clear = REG_READ(ah, AR_RCCNT);
1078 rx_frame = rf; 1029 ah->cc.rx_frame = REG_READ(ah, AR_RFCNT);
1079 rx_clear = rc; 1030 ah->cc.tx_frame = REG_READ(ah, AR_TFCNT);
1080 tx_frame = tf; 1031
1032 /* prevent wraparound */
1033 if (ah->cc.cycles & BIT(31))
1034 clear = true;
1035
1036#define CC_DELTA(_field, _reg) ah->cc_delta._field += ah->cc._field - cc._field
1037 CC_DELTA(cycles, AR_CCCNT);
1038 CC_DELTA(rx_frame, AR_RFCNT);
1039 CC_DELTA(rx_clear, AR_RCCNT);
1040 CC_DELTA(tx_frame, AR_TFCNT);
1041#undef CC_DELTA
1042
1043 ah->listen_time += (ah->cc.cycles - cc.cycles) -
1044 ((ah->cc.rx_frame - cc.rx_frame) +
1045 (ah->cc.tx_frame - cc.tx_frame));
1046
1047skip:
1048 if (clear) {
1049 REG_WRITE(ah, AR_CCCNT, 0);
1050 REG_WRITE(ah, AR_RFCNT, 0);
1051 REG_WRITE(ah, AR_RCCNT, 0);
1052 REG_WRITE(ah, AR_TFCNT, 0);
1053 memset(&ah->cc, 0, sizeof(ah->cc));
1054 }
1081 1055
1082 return good; 1056 /* unfreeze counters */
1057 REG_WRITE(ah, AR_MIBC, 0);
1083} 1058}
1084 1059
1085/* 1060/*
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h
index f4d0a4d48b37..15f9d67a18c8 100644
--- a/drivers/net/wireless/ath/ath9k/ani.h
+++ b/drivers/net/wireless/ath/ath9k/ani.h
@@ -93,6 +93,13 @@ struct ath9k_mib_stats {
93 u32 beacons; 93 u32 beacons;
94}; 94};
95 95
96struct ath_cycle_counters {
97 u32 cycles;
98 u32 rx_frame;
99 u32 rx_clear;
100 u32 tx_frame;
101};
102
96/* INI default values for ANI registers */ 103/* INI default values for ANI registers */
97struct ath9k_ani_default { 104struct ath9k_ani_default {
98 u16 m1ThreshLow; 105 u16 m1ThreshLow;
@@ -130,9 +137,6 @@ struct ar5416AniState {
130 int32_t rssiThrLow; 137 int32_t rssiThrLow;
131 int32_t rssiThrHigh; 138 int32_t rssiThrHigh;
132 u32 noiseFloor; 139 u32 noiseFloor;
133 u32 txFrameCount;
134 u32 rxFrameCount;
135 u32 cycleCount;
136 u32 ofdmPhyErrCount; 140 u32 ofdmPhyErrCount;
137 u32 cckPhyErrCount; 141 u32 cckPhyErrCount;
138 u32 ofdmPhyErrBase; 142 u32 ofdmPhyErrBase;
@@ -166,8 +170,7 @@ struct ar5416Stats {
166 170
167void ath9k_enable_mib_counters(struct ath_hw *ah); 171void ath9k_enable_mib_counters(struct ath_hw *ah);
168void ath9k_hw_disable_mib_counters(struct ath_hw *ah); 172void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
169u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, 173void ath9k_hw_update_cycle_counters(struct ath_hw *ah);
170 u32 *rxf_pcnt, u32 *txf_pcnt);
171void ath9k_hw_ani_setup(struct ath_hw *ah); 174void ath9k_hw_ani_setup(struct ath_hw *ah);
172void ath9k_hw_ani_init(struct ath_hw *ah); 175void ath9k_hw_ani_init(struct ath_hw *ah);
173int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, 176int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index 525671f52b45..a11ca0247793 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -1225,8 +1225,7 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah,
1225 aniState->firstepLevel, 1225 aniState->firstepLevel,
1226 aniState->listenTime); 1226 aniState->listenTime);
1227 ath_print(common, ATH_DBG_ANI, 1227 ath_print(common, ATH_DBG_ANI,
1228 "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", 1228 "ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
1229 aniState->cycleCount,
1230 aniState->ofdmPhyErrCount, 1229 aniState->ofdmPhyErrCount,
1231 aniState->cckPhyErrCount); 1230 aniState->cckPhyErrCount);
1232 1231
@@ -1478,15 +1477,13 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
1478 1477
1479 ath_print(common, ATH_DBG_ANI, 1478 ath_print(common, ATH_DBG_ANI,
1480 "ANI parameters: SI=%d, ofdmWS=%s FS=%d " 1479 "ANI parameters: SI=%d, ofdmWS=%s FS=%d "
1481 "MRCcck=%s listenTime=%d CC=%d listen=%d " 1480 "MRCcck=%s listenTime=%d "
1482 "ofdmErrs=%d cckErrs=%d\n", 1481 "ofdmErrs=%d cckErrs=%d\n",
1483 aniState->spurImmunityLevel, 1482 aniState->spurImmunityLevel,
1484 !aniState->ofdmWeakSigDetectOff ? "on" : "off", 1483 !aniState->ofdmWeakSigDetectOff ? "on" : "off",
1485 aniState->firstepLevel, 1484 aniState->firstepLevel,
1486 !aniState->mrcCCKOff ? "on" : "off", 1485 !aniState->mrcCCKOff ? "on" : "off",
1487 aniState->listenTime, 1486 aniState->listenTime,
1488 aniState->cycleCount,
1489 aniState->listenTime,
1490 aniState->ofdmPhyErrCount, 1487 aniState->ofdmPhyErrCount,
1491 aniState->cckPhyErrCount); 1488 aniState->cckPhyErrCount);
1492 return true; 1489 return true;
@@ -1579,8 +1576,6 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
1579 aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW; 1576 aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
1580 aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG; 1577 aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
1581 aniState->mrcCCKOff = true; /* not available on pre AR9003 */ 1578 aniState->mrcCCKOff = true; /* not available on pre AR9003 */
1582
1583 aniState->cycleCount = 0;
1584} 1579}
1585 1580
1586static void ar5008_hw_set_nf_limits(struct ath_hw *ah) 1581static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index a491854fa38a..e15574caf61a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -1005,15 +1005,13 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
1005 1005
1006 ath_print(common, ATH_DBG_ANI, 1006 ath_print(common, ATH_DBG_ANI,
1007 "ANI parameters: SI=%d, ofdmWS=%s FS=%d " 1007 "ANI parameters: SI=%d, ofdmWS=%s FS=%d "
1008 "MRCcck=%s listenTime=%d CC=%d listen=%d " 1008 "MRCcck=%s listenTime=%d "
1009 "ofdmErrs=%d cckErrs=%d\n", 1009 "ofdmErrs=%d cckErrs=%d\n",
1010 aniState->spurImmunityLevel, 1010 aniState->spurImmunityLevel,
1011 !aniState->ofdmWeakSigDetectOff ? "on" : "off", 1011 !aniState->ofdmWeakSigDetectOff ? "on" : "off",
1012 aniState->firstepLevel, 1012 aniState->firstepLevel,
1013 !aniState->mrcCCKOff ? "on" : "off", 1013 !aniState->mrcCCKOff ? "on" : "off",
1014 aniState->listenTime, 1014 aniState->listenTime,
1015 aniState->cycleCount,
1016 aniState->listenTime,
1017 aniState->ofdmPhyErrCount, 1015 aniState->ofdmPhyErrCount,
1018 aniState->cckPhyErrCount); 1016 aniState->cckPhyErrCount);
1019 return true; 1017 return true;
@@ -1116,8 +1114,6 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
1116 aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW; 1114 aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
1117 aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG; 1115 aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
1118 aniState->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK; 1116 aniState->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK;
1119
1120 aniState->cycleCount = 0;
1121} 1117}
1122 1118
1123void ar9003_hw_attach_phy_ops(struct ath_hw *ah) 1119void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
@@ -1232,7 +1228,7 @@ void ar9003_hw_bb_watchdog_read(struct ath_hw *ah)
1232void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah) 1228void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah)
1233{ 1229{
1234 struct ath_common *common = ath9k_hw_common(ah); 1230 struct ath_common *common = ath9k_hw_common(ah);
1235 u32 rxc_pcnt = 0, rxf_pcnt = 0, txf_pcnt = 0, status; 1231 u32 status;
1236 1232
1237 if (likely(!(common->debug_mask & ATH_DBG_RESET))) 1233 if (likely(!(common->debug_mask & ATH_DBG_RESET)))
1238 return; 1234 return;
@@ -1261,11 +1257,13 @@ void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah)
1261 "** BB mode: BB_gen_controls=0x%08x **\n", 1257 "** BB mode: BB_gen_controls=0x%08x **\n",
1262 REG_READ(ah, AR_PHY_GEN_CTRL)); 1258 REG_READ(ah, AR_PHY_GEN_CTRL));
1263 1259
1264 if (ath9k_hw_GetMibCycleCountsPct(ah, &rxc_pcnt, &rxf_pcnt, &txf_pcnt)) 1260 ath9k_hw_update_cycle_counters(ah);
1261#define PCT(_field) (ah->cc_delta._field * 100 / ah->cc_delta.cycles)
1262 if (ah->cc_delta.cycles)
1265 ath_print(common, ATH_DBG_RESET, 1263 ath_print(common, ATH_DBG_RESET,
1266 "** BB busy times: rx_clear=%d%%, " 1264 "** BB busy times: rx_clear=%d%%, "
1267 "rx_frame=%d%%, tx_frame=%d%% **\n", 1265 "rx_frame=%d%%, tx_frame=%d%% **\n",
1268 rxc_pcnt, rxf_pcnt, txf_pcnt); 1266 PCT(rx_clear), PCT(rx_frame), PCT(tx_frame));
1269 1267
1270 ath_print(common, ATH_DBG_RESET, 1268 ath_print(common, ATH_DBG_RESET,
1271 "==== BB update: done ====\n\n"); 1269 "==== BB update: done ====\n\n");
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 246c707cea00..87dbb8502469 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -765,6 +765,8 @@ struct ath_hw {
765 int coarse_low[5]; 765 int coarse_low[5];
766 int firpwr[5]; 766 int firpwr[5];
767 enum ath9k_ani_cmd ani_function; 767 enum ath9k_ani_cmd ani_function;
768 struct ath_cycle_counters cc, cc_delta;
769 int32_t listen_time;
768 770
769 /* Bluetooth coexistance */ 771 /* Bluetooth coexistance */
770 struct ath_btcoex_hw btcoex_hw; 772 struct ath_btcoex_hw btcoex_hw;