aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2013-12-14 12:03:45 -0500
committerJohn W. Linville <linville@tuxdriver.com>2013-12-18 15:23:34 -0500
commita35051ce1733f524c12a8246641ded5d0409817d (patch)
tree4a6f3b71e6a4f63191ef6b8c277f119900f44d7f /drivers/net/wireless/ath
parent4ed15762dce67192d4662860470a8be1f6d5fd53 (diff)
ath9k: properly preserve TSF across reset
The beacon code previously reset TSF on every configuration call, as some of the code was not prepared to properly calculate nexttbtt based on current TSF. This patch adds a common function for calculating nexttbtt and moves the TSF reset to driver start. This should improve AP mode compatibility with various stations that expect the TSF to not randomly jump due to hardware resets. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c88
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c2
2 files changed, 45 insertions, 45 deletions
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 5128856d77d2..78ffe762e26c 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -431,6 +431,33 @@ static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
431 ath9k_hw_enable_interrupts(ah); 431 ath9k_hw_enable_interrupts(ah);
432} 432}
433 433
434/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */
435static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu)
436{
437 u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo;
438
439 tsf_mod = tsf & (BIT(10) - 1);
440 tsf_hi = tsf >> 32;
441 tsf_lo = ((u32) tsf) >> 10;
442
443 mod_hi = tsf_hi % div_tu;
444 mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu;
445
446 return (mod_lo << 10) | tsf_mod;
447}
448
449static u32 ath9k_get_next_tbtt(struct ath_softc *sc, u64 tsf,
450 unsigned int interval)
451{
452 struct ath_hw *ah = sc->sc_ah;
453 unsigned int offset;
454
455 tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time);
456 offset = ath9k_mod_tsf64_tu(tsf, interval);
457
458 return (u32) tsf + TU_TO_USEC(interval) - offset;
459}
460
434/* 461/*
435 * For multi-bss ap support beacons are either staggered evenly over N slots or 462 * For multi-bss ap support beacons are either staggered evenly over N slots or
436 * burst together. For the former arrange for the SWBA to be delivered for each 463 * burst together. For the former arrange for the SWBA to be delivered for each
@@ -446,7 +473,8 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
446 /* NB: the beacon interval is kept internally in TU's */ 473 /* NB: the beacon interval is kept internally in TU's */
447 intval = TU_TO_USEC(conf->beacon_interval); 474 intval = TU_TO_USEC(conf->beacon_interval);
448 intval /= ATH_BCBUF; 475 intval /= ATH_BCBUF;
449 nexttbtt = intval; 476 nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah),
477 conf->beacon_interval);
450 478
451 if (conf->enable_beacon) 479 if (conf->enable_beacon)
452 ah->imask |= ATH9K_INT_SWBA; 480 ah->imask |= ATH9K_INT_SWBA;
@@ -458,7 +486,7 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
458 (conf->enable_beacon) ? "Enable" : "Disable", 486 (conf->enable_beacon) ? "Enable" : "Disable",
459 nexttbtt, intval, conf->beacon_interval); 487 nexttbtt, intval, conf->beacon_interval);
460 488
461 ath9k_beacon_init(sc, nexttbtt, intval, true); 489 ath9k_beacon_init(sc, nexttbtt, intval, false);
462} 490}
463 491
464/* 492/*
@@ -475,10 +503,9 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
475 struct ath_hw *ah = sc->sc_ah; 503 struct ath_hw *ah = sc->sc_ah;
476 struct ath_common *common = ath9k_hw_common(ah); 504 struct ath_common *common = ath9k_hw_common(ah);
477 struct ath9k_beacon_state bs; 505 struct ath9k_beacon_state bs;
478 int dtimperiod, dtimcount, sleepduration; 506 int dtim_intval, sleepduration;
479 u32 nexttbtt = 0, intval, tsftu; 507 u32 nexttbtt = 0, intval;
480 u64 tsf; 508 u64 tsf;
481 int num_beacons, offset, dtim_dec_count;
482 509
483 /* No need to configure beacon if we are not associated */ 510 /* No need to configure beacon if we are not associated */
484 if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { 511 if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
@@ -494,11 +521,7 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
494 * Setup dtim parameters according to 521 * Setup dtim parameters according to
495 * last beacon we received (which may be none). 522 * last beacon we received (which may be none).
496 */ 523 */
497 dtimperiod = conf->dtim_period; 524 dtim_intval = intval * conf->dtim_period;
498 dtimcount = conf->dtim_count;
499 if (dtimcount >= dtimperiod) /* NB: sanity check */
500 dtimcount = 0;
501
502 sleepduration = conf->listen_interval * intval; 525 sleepduration = conf->listen_interval * intval;
503 526
504 /* 527 /*
@@ -506,24 +529,14 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
506 * TSF and calculate dtim state for the result. 529 * TSF and calculate dtim state for the result.
507 */ 530 */
508 tsf = ath9k_hw_gettsf64(ah); 531 tsf = ath9k_hw_gettsf64(ah);
509 tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; 532 nexttbtt = ath9k_get_next_tbtt(sc, tsf, intval);
510
511 num_beacons = tsftu / intval + 1;
512 offset = tsftu % intval;
513 nexttbtt = tsftu - offset;
514 if (offset)
515 nexttbtt += intval;
516
517 /* DTIM Beacon every dtimperiod Beacon */
518 dtim_dec_count = num_beacons % dtimperiod;
519 dtimcount -= dtim_dec_count;
520 if (dtimcount < 0)
521 dtimcount += dtimperiod;
522 533
523 bs.bs_intval = TU_TO_USEC(intval); 534 bs.bs_intval = TU_TO_USEC(intval);
524 bs.bs_nexttbtt = TU_TO_USEC(nexttbtt); 535 bs.bs_dtimperiod = conf->dtim_period * bs.bs_intval;
525 bs.bs_dtimperiod = dtimperiod * bs.bs_intval; 536 bs.bs_nexttbtt = nexttbtt;
526 bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount * bs.bs_intval; 537 bs.bs_nextdtim = nexttbtt;
538 if (conf->dtim_period > 1)
539 bs.bs_nextdtim = ath9k_get_next_tbtt(sc, tsf, dtim_intval);
527 540
528 /* 541 /*
529 * Calculate the number of consecutive beacons to miss* before taking 542 * Calculate the number of consecutive beacons to miss* before taking
@@ -559,7 +572,6 @@ static void ath9k_beacon_config_sta(struct ath_softc *sc,
559 /* TSF out of range threshold fixed at 1 second */ 572 /* TSF out of range threshold fixed at 1 second */
560 bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; 573 bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
561 574
562 ath_dbg(common, BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
563 ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n", 575 ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n",
564 bs.bs_bmissthreshold, bs.bs_sleepduration); 576 bs.bs_bmissthreshold, bs.bs_sleepduration);
565 577
@@ -584,25 +596,11 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
584 596
585 intval = TU_TO_USEC(conf->beacon_interval); 597 intval = TU_TO_USEC(conf->beacon_interval);
586 598
587 if (conf->ibss_creator) { 599 if (conf->ibss_creator)
588 nexttbtt = intval; 600 nexttbtt = intval;
589 } else { 601 else
590 u32 tbtt, offset, tsftu; 602 nexttbtt = ath9k_get_next_tbtt(sc, ath9k_hw_gettsf64(ah),
591 u64 tsf; 603 conf->beacon_interval);
592
593 /*
594 * Pull nexttbtt forward to reflect the current
595 * sync'd TSF.
596 */
597 tsf = ath9k_hw_gettsf64(ah);
598 tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
599 offset = tsftu % conf->beacon_interval;
600 tbtt = tsftu - offset;
601 if (offset)
602 tbtt += conf->beacon_interval;
603
604 nexttbtt = TU_TO_USEC(tbtt);
605 }
606 604
607 if (conf->enable_beacon) 605 if (conf->enable_beacon)
608 ah->imask |= ATH9K_INT_SWBA; 606 ah->imask |= ATH9K_INT_SWBA;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 4798f6ae061e..6a231201c7dc 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -760,6 +760,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
760 */ 760 */
761 ath9k_cmn_init_crypto(sc->sc_ah); 761 ath9k_cmn_init_crypto(sc->sc_ah);
762 762
763 ath9k_hw_reset_tsf(ah);
764
763 spin_unlock_bh(&sc->sc_pcu_lock); 765 spin_unlock_bh(&sc->sc_pcu_lock);
764 766
765 mutex_unlock(&sc->mutex); 767 mutex_unlock(&sc->mutex);