diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/pcu.c | 31 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.c | 19 |
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 | */ |
506 | u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) | 508 | u64 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 | } |
2421 | EXPORT_SYMBOL(ath9k_hw_write_associd); | 2421 | EXPORT_SYMBOL(ath9k_hw_write_associd); |
2422 | 2422 | ||
2423 | #define ATH9K_MAX_TSF_READ 10 | ||
2424 | |||
2423 | u64 ath9k_hw_gettsf64(struct ath_hw *ah) | 2425 | u64 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 | } |
2432 | EXPORT_SYMBOL(ath9k_hw_gettsf64); | 2443 | EXPORT_SYMBOL(ath9k_hw_gettsf64); |
2433 | 2444 | ||