aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenoit Papillault <benoit.papillault@free.fr>2010-04-15 18:07:26 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-04-16 15:46:54 -0400
commit1c0fc65e6de4e941ff483df445e721d6edb1f84b (patch)
tree817e2d467d656b845b649f5ec883fbf100bc4b1e
parent733f0ea4498a24db5b8ac048ef99983600f1eff9 (diff)
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>
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c31
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c19
2 files changed, 44 insertions, 6 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)
496* Beacon control * 496* Beacon control *
497\****************/ 497\****************/
498 498
499#define ATH5K_MAX_TSF_READ 10
500
499/** 501/**
500 * ath5k_hw_get_tsf64 - Get the full 64bit TSF 502 * ath5k_hw_get_tsf64 - Get the full 64bit TSF
501 * 503 *
@@ -505,10 +507,35 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
505 */ 507 */
506u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) 508u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
507{ 509{
508 u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32); 510 u32 tsf_lower, tsf_upper1, tsf_upper2;
511 int i;
512
513 /*
514 * While reading TSF upper and then lower part, the clock is still
515 * counting (or jumping in case of IBSS merge) so we might get
516 * inconsistent values. To avoid this, we read the upper part again
517 * and check it has not been changed. We make the hypothesis that a
518 * maximum of 3 changes can happens in a row (we use 10 as a safe
519 * value).
520 *
521 * Impact on performance is pretty small, since in most cases, only
522 * 3 register reads are needed.
523 */
524
525 tsf_upper1 = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
526 for (i = 0; i < ATH5K_MAX_TSF_READ; i++) {
527 tsf_lower = ath5k_hw_reg_read(ah, AR5K_TSF_L32);
528 tsf_upper2 = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
529 if (tsf_upper2 == tsf_upper1)
530 break;
531 tsf_upper1 = tsf_upper2;
532 }
533
534 WARN_ON( i == ATH5K_MAX_TSF_READ );
535
509 ATH5K_TRACE(ah->ah_sc); 536 ATH5K_TRACE(ah->ah_sc);
510 537
511 return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32); 538 return (((u64)tsf_upper1 << 32) | tsf_lower);
512} 539}
513 540
514/** 541/**
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)
2420} 2420}
2421EXPORT_SYMBOL(ath9k_hw_write_associd); 2421EXPORT_SYMBOL(ath9k_hw_write_associd);
2422 2422
2423#define ATH9K_MAX_TSF_READ 10
2424
2423u64 ath9k_hw_gettsf64(struct ath_hw *ah) 2425u64 ath9k_hw_gettsf64(struct ath_hw *ah)
2424{ 2426{
2425 u64 tsf; 2427 u32 tsf_lower, tsf_upper1, tsf_upper2;
2428 int i;
2429
2430 tsf_upper1 = REG_READ(ah, AR_TSF_U32);
2431 for (i = 0; i < ATH9K_MAX_TSF_READ; i++) {
2432 tsf_lower = REG_READ(ah, AR_TSF_L32);
2433 tsf_upper2 = REG_READ(ah, AR_TSF_U32);
2434 if (tsf_upper2 == tsf_upper1)
2435 break;
2436 tsf_upper1 = tsf_upper2;
2437 }
2426 2438
2427 tsf = REG_READ(ah, AR_TSF_U32); 2439 WARN_ON( i == ATH9K_MAX_TSF_READ );
2428 tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32);
2429 2440
2430 return tsf; 2441 return (((u64)tsf_upper1 << 32) | tsf_lower);
2431} 2442}
2432EXPORT_SYMBOL(ath9k_hw_gettsf64); 2443EXPORT_SYMBOL(ath9k_hw_gettsf64);
2433 2444