diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-04-23 14:43:45 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-04-23 14:43:45 -0400 |
commit | 3b51cc996e81d8a113416d8094fa4a88f8360a51 (patch) | |
tree | e75b98b228bb4e456c30673fcc4b56ffa1d09cf5 /drivers/net/wireless/ath/ath5k/pcu.c | |
parent | c68ed255265968c3948fa2678bf59d15c471b055 (diff) | |
parent | 672724403b42da1d276c6cf811e8e34d15efd964 (diff) |
Merge branch 'master' into for-davem
Conflicts:
drivers/net/wireless/ath/ath9k/phy.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-debugfs.c
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/pcu.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/pcu.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 174412fc81f8..5212e275f1c7 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/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); } /** |