From c0c532551afc0279ebf2fd7bf460a075044ef50a Mon Sep 17 00:00:00 2001 From: Benoit Papillault Date: Fri, 16 Apr 2010 00:07:26 +0200 Subject: [PATCH] --- yaml --- r: 194453 b: refs/heads/master c: 1c0fc65e6de4e941ff483df445e721d6edb1f84b h: refs/heads/master i: 194451: 3ca862066dd7a3594375672766098f63d4feb570 v: v3 --- [refs] | 2 +- trunk/drivers/net/wireless/ath/ath5k/pcu.c | 31 ++++++++++++++++++++-- trunk/drivers/net/wireless/ath/ath9k/hw.c | 19 ++++++++++--- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/[refs] b/[refs] index ce0c44afc865..4c581d5623ff 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 733f0ea4498a24db5b8ac048ef99983600f1eff9 +refs/heads/master: 1c0fc65e6de4e941ff483df445e721d6edb1f84b diff --git a/trunk/drivers/net/wireless/ath/ath5k/pcu.c b/trunk/drivers/net/wireless/ath/ath5k/pcu.c index 174412fc81f8..5212e275f1c7 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/pcu.c +++ b/trunk/drivers/net/wireless/ath/ath5k/pcu.c @@ -496,6 +496,8 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) * Beacon control * \****************/ +#define ATH5K_MAX_TSF_READ 10 + /** * ath5k_hw_get_tsf64 - Get the full 64bit TSF * @@ -505,10 +507,35 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) */ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) { - u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32); + u32 tsf_lower, tsf_upper1, tsf_upper2; + int i; + + /* + * While reading TSF upper and then lower part, the clock is still + * counting (or jumping in case of IBSS merge) so we might get + * inconsistent values. To avoid this, we read the upper part again + * and check it has not been changed. We make the hypothesis that a + * maximum of 3 changes can happens in a row (we use 10 as a safe + * value). + * + * Impact on performance is pretty small, since in most cases, only + * 3 register reads are needed. + */ + + tsf_upper1 = ath5k_hw_reg_read(ah, AR5K_TSF_U32); + for (i = 0; i < ATH5K_MAX_TSF_READ; i++) { + tsf_lower = ath5k_hw_reg_read(ah, AR5K_TSF_L32); + tsf_upper2 = ath5k_hw_reg_read(ah, AR5K_TSF_U32); + if (tsf_upper2 == tsf_upper1) + break; + tsf_upper1 = tsf_upper2; + } + + WARN_ON( i == ATH5K_MAX_TSF_READ ); + ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32); + return (((u64)tsf_upper1 << 32) | tsf_lower); } /** diff --git a/trunk/drivers/net/wireless/ath/ath9k/hw.c b/trunk/drivers/net/wireless/ath/ath9k/hw.c index 35f5cf40a990..894f5fc7489e 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/hw.c +++ b/trunk/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);