summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/hw.c
diff options
context:
space:
mode:
authorBenoit Papillault <benoit.papillault@free.fr>2010-04-16 00:07:26 +0200
committerJohn W. Linville <linville@tuxdriver.com>2010-04-16 15:46:54 -0400
commit1c0fc65e6de4e941ff483df445e721d6edb1f84b (patch)
tree817e2d467d656b845b649f5ec883fbf100bc4b1e /drivers/net/wireless/ath/ath9k/hw.c
parent733f0ea4498a24db5b8ac048ef99983600f1eff9 (diff)
downloadlinux-stable-1c0fc65e6de4e941ff483df445e721d6edb1f84b.tar.gz
linux-stable-1c0fc65e6de4e941ff483df445e721d6edb1f84b.tar.bz2
linux-stable-1c0fc65e6de4e941ff483df445e721d6edb1f84b.zip
ath5k/ath9k: Fix 64 bits TSF reads
According to tests, both TSF lower and upper registers kept counting, so the higher part could have been updated after the lower part has been read, as shown in the following log where the upper part is read first and the lower part next. tsf = {00000003-fffffffd} tsf = {00000003-00000001} tsf = {00000004-0000000b} This patch corrects this by checking that the upper part has not been changed while the lower part was read. It has been tested in an IBSS network where artifical IBSS merges have been done in order to trigger hundreds of rollover for the TSF lower part. It follows the logic mentionned by Derek, with only 2 register reads needed at each additional steps instead of 3 (the minimum number of register reads is still 3). Signed-off-by: Benoit Papillault <benoit.papillault@free.fr> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/hw.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 35f5cf40a990..894f5fc7489e 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2420,14 +2420,25 @@ void ath9k_hw_write_associd(struct ath_hw *ah)
}
EXPORT_SYMBOL(ath9k_hw_write_associd);
+#define ATH9K_MAX_TSF_READ 10
+
u64 ath9k_hw_gettsf64(struct ath_hw *ah)
{
- u64 tsf;
+ u32 tsf_lower, tsf_upper1, tsf_upper2;
+ int i;
+
+ tsf_upper1 = REG_READ(ah, AR_TSF_U32);
+ for (i = 0; i < ATH9K_MAX_TSF_READ; i++) {
+ tsf_lower = REG_READ(ah, AR_TSF_L32);
+ tsf_upper2 = REG_READ(ah, AR_TSF_U32);
+ if (tsf_upper2 == tsf_upper1)
+ break;
+ tsf_upper1 = tsf_upper2;
+ }
- tsf = REG_READ(ah, AR_TSF_U32);
- tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32);
+ WARN_ON( i == ATH9K_MAX_TSF_READ );
- return tsf;
+ return (((u64)tsf_upper1 << 32) | tsf_lower);
}
EXPORT_SYMBOL(ath9k_hw_gettsf64);