diff options
author | Felix Fietkau <nbd@openwrt.org> | 2011-03-22 16:54:17 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-03-30 14:15:17 -0400 |
commit | dd347f2fb2ddb20a80e9a8285252bf208ab91398 (patch) | |
tree | 9e1a33ea4f50dd9b116e80da2fd6250d570eb001 /drivers/net/wireless/ath/ath9k/beacon.c | |
parent | f39de992540cf68cc865498242f963f70f7e97b3 (diff) |
ath9k: fix beacon timer handling issues
AP mode beacon timers in ath9k are configured in milliseconds, which breaks
when increasing ATH_BCBUF to 8 instead of 4 (due to rounding errors).
Since the hardware timers are actually configured in microseconds, it's
better to let the driver use that unit directly.
To be able to do that, the beacon interval parameter abuse for passing
certain flags needs to be removed. This is easy to do, because those flags
are completely unnecessary anyway. ATH9K_BEACON_ENA is ignored,
ATH9K_BEACON_RESET_TSF can be replaced with calling ath9k_hw_reset_tsf
from the driver directly.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/beacon.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/beacon.c | 78 |
1 files changed, 31 insertions, 47 deletions
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 6d2a545fc35e..b5eab2f55824 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -57,8 +57,8 @@ int ath_beaconq_config(struct ath_softc *sc) | |||
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Associates the beacon frame buffer with a transmit descriptor. Will set | 59 | * Associates the beacon frame buffer with a transmit descriptor. Will set |
60 | * up all required antenna switch parameters, rate codes, and channel flags. | 60 | * up rate codes, and channel flags. Beacons are always sent out at the |
61 | * Beacons are always sent out at the lowest rate, and are not retried. | 61 | * lowest rate, and are not retried. |
62 | */ | 62 | */ |
63 | static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, | 63 | static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, |
64 | struct ath_buf *bf, int rateidx) | 64 | struct ath_buf *bf, int rateidx) |
@@ -68,7 +68,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, | |||
68 | struct ath_common *common = ath9k_hw_common(ah); | 68 | struct ath_common *common = ath9k_hw_common(ah); |
69 | struct ath_desc *ds; | 69 | struct ath_desc *ds; |
70 | struct ath9k_11n_rate_series series[4]; | 70 | struct ath9k_11n_rate_series series[4]; |
71 | int flags, antenna, ctsrate = 0, ctsduration = 0; | 71 | int flags, ctsrate = 0, ctsduration = 0; |
72 | struct ieee80211_supported_band *sband; | 72 | struct ieee80211_supported_band *sband; |
73 | u8 rate = 0; | 73 | u8 rate = 0; |
74 | 74 | ||
@@ -76,12 +76,6 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, | |||
76 | flags = ATH9K_TXDESC_NOACK; | 76 | flags = ATH9K_TXDESC_NOACK; |
77 | 77 | ||
78 | ds->ds_link = 0; | 78 | ds->ds_link = 0; |
79 | /* | ||
80 | * Switch antenna every beacon. | ||
81 | * Should only switch every beacon period, not for every SWBA | ||
82 | * XXX assumes two antennae | ||
83 | */ | ||
84 | antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); | ||
85 | 79 | ||
86 | sband = &sc->sbands[common->hw->conf.channel->band]; | 80 | sband = &sc->sbands[common->hw->conf.channel->band]; |
87 | rate = sband->bitrates[rateidx].hw_value; | 81 | rate = sband->bitrates[rateidx].hw_value; |
@@ -278,7 +272,7 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) | |||
278 | return -ENOMEM; | 272 | return -ENOMEM; |
279 | 273 | ||
280 | tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; | 274 | tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; |
281 | sc->beacon.bc_tstamp = le64_to_cpu(tstamp); | 275 | sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp); |
282 | /* Calculate a TSF adjustment factor required for staggered beacons. */ | 276 | /* Calculate a TSF adjustment factor required for staggered beacons. */ |
283 | if (avp->av_bslot > 0) { | 277 | if (avp->av_bslot > 0) { |
284 | u64 tsfadjust; | 278 | u64 tsfadjust; |
@@ -294,8 +288,8 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) | |||
294 | * adjustment. Other slots are adjusted to get the timestamp | 288 | * adjustment. Other slots are adjusted to get the timestamp |
295 | * close to the TBTT for the BSS. | 289 | * close to the TBTT for the BSS. |
296 | */ | 290 | */ |
297 | tsfadjust = intval * avp->av_bslot / ATH_BCBUF; | 291 | tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF; |
298 | avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); | 292 | avp->tsf_adjust = cpu_to_le64(tsfadjust); |
299 | 293 | ||
300 | ath_dbg(common, ATH_DBG_BEACON, | 294 | ath_dbg(common, ATH_DBG_BEACON, |
301 | "stagger beacons, bslot %d intval %u tsfadjust %llu\n", | 295 | "stagger beacons, bslot %d intval %u tsfadjust %llu\n", |
@@ -401,8 +395,9 @@ void ath_beacon_tasklet(unsigned long data) | |||
401 | intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; | 395 | intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; |
402 | 396 | ||
403 | tsf = ath9k_hw_gettsf64(ah); | 397 | tsf = ath9k_hw_gettsf64(ah); |
404 | tsftu = TSF_TO_TU(tsf>>32, tsf); | 398 | tsf += TU_TO_USEC(ah->config.sw_beacon_response_time); |
405 | slot = ((tsftu % intval) * ATH_BCBUF) / intval; | 399 | tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF); |
400 | slot = (tsftu % (intval * ATH_BCBUF)) / intval; | ||
406 | /* | 401 | /* |
407 | * Reverse the slot order to get slot 0 on the TBTT offset that does | 402 | * Reverse the slot order to get slot 0 on the TBTT offset that does |
408 | * not require TSF adjustment and other slots adding | 403 | * not require TSF adjustment and other slots adding |
@@ -415,7 +410,7 @@ void ath_beacon_tasklet(unsigned long data) | |||
415 | 410 | ||
416 | ath_dbg(common, ATH_DBG_BEACON, | 411 | ath_dbg(common, ATH_DBG_BEACON, |
417 | "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", | 412 | "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", |
418 | slot, tsf, tsftu, intval, vif); | 413 | slot, tsf, tsftu / ATH_BCBUF, intval, vif); |
419 | 414 | ||
420 | bfaddr = 0; | 415 | bfaddr = 0; |
421 | if (vif) { | 416 | if (vif) { |
@@ -463,13 +458,17 @@ static void ath9k_beacon_init(struct ath_softc *sc, | |||
463 | u32 next_beacon, | 458 | u32 next_beacon, |
464 | u32 beacon_period) | 459 | u32 beacon_period) |
465 | { | 460 | { |
466 | if (beacon_period & ATH9K_BEACON_RESET_TSF) | 461 | if (sc->sc_flags & SC_OP_TSF_RESET) { |
467 | ath9k_ps_wakeup(sc); | 462 | ath9k_ps_wakeup(sc); |
463 | ath9k_hw_reset_tsf(sc->sc_ah); | ||
464 | } | ||
468 | 465 | ||
469 | ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); | 466 | ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); |
470 | 467 | ||
471 | if (beacon_period & ATH9K_BEACON_RESET_TSF) | 468 | if (sc->sc_flags & SC_OP_TSF_RESET) { |
472 | ath9k_ps_restore(sc); | 469 | ath9k_ps_restore(sc); |
470 | sc->sc_flags &= ~SC_OP_TSF_RESET; | ||
471 | } | ||
473 | } | 472 | } |
474 | 473 | ||
475 | /* | 474 | /* |
@@ -484,18 +483,14 @@ static void ath_beacon_config_ap(struct ath_softc *sc, | |||
484 | u32 nexttbtt, intval; | 483 | u32 nexttbtt, intval; |
485 | 484 | ||
486 | /* NB: the beacon interval is kept internally in TU's */ | 485 | /* NB: the beacon interval is kept internally in TU's */ |
487 | intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; | 486 | intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); |
488 | intval /= ATH_BCBUF; /* for staggered beacons */ | 487 | intval /= ATH_BCBUF; /* for staggered beacons */ |
489 | nexttbtt = intval; | 488 | nexttbtt = intval; |
490 | 489 | ||
491 | if (sc->sc_flags & SC_OP_TSF_RESET) | ||
492 | intval |= ATH9K_BEACON_RESET_TSF; | ||
493 | |||
494 | /* | 490 | /* |
495 | * In AP mode we enable the beacon timers and SWBA interrupts to | 491 | * In AP mode we enable the beacon timers and SWBA interrupts to |
496 | * prepare beacon frames. | 492 | * prepare beacon frames. |
497 | */ | 493 | */ |
498 | intval |= ATH9K_BEACON_ENA; | ||
499 | ah->imask |= ATH9K_INT_SWBA; | 494 | ah->imask |= ATH9K_INT_SWBA; |
500 | ath_beaconq_config(sc); | 495 | ath_beaconq_config(sc); |
501 | 496 | ||
@@ -505,11 +500,6 @@ static void ath_beacon_config_ap(struct ath_softc *sc, | |||
505 | ath9k_beacon_init(sc, nexttbtt, intval); | 500 | ath9k_beacon_init(sc, nexttbtt, intval); |
506 | sc->beacon.bmisscnt = 0; | 501 | sc->beacon.bmisscnt = 0; |
507 | ath9k_hw_set_interrupts(ah, ah->imask); | 502 | ath9k_hw_set_interrupts(ah, ah->imask); |
508 | |||
509 | /* Clear the reset TSF flag, so that subsequent beacon updation | ||
510 | will not reset the HW TSF. */ | ||
511 | |||
512 | sc->sc_flags &= ~SC_OP_TSF_RESET; | ||
513 | } | 503 | } |
514 | 504 | ||
515 | /* | 505 | /* |
@@ -643,25 +633,20 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, | |||
643 | { | 633 | { |
644 | struct ath_hw *ah = sc->sc_ah; | 634 | struct ath_hw *ah = sc->sc_ah; |
645 | struct ath_common *common = ath9k_hw_common(ah); | 635 | struct ath_common *common = ath9k_hw_common(ah); |
646 | u64 tsf; | 636 | u32 tsf, delta, intval, nexttbtt; |
647 | u32 tsftu, intval, nexttbtt; | 637 | |
648 | 638 | tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE); | |
649 | intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; | 639 | intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); |
650 | 640 | ||
651 | 641 | if (!sc->beacon.bc_tstamp) | |
652 | /* Pull nexttbtt forward to reflect the current TSF */ | 642 | nexttbtt = tsf + intval; |
653 | 643 | else { | |
654 | nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); | 644 | if (tsf > sc->beacon.bc_tstamp) |
655 | if (nexttbtt == 0) | 645 | delta = (tsf - sc->beacon.bc_tstamp); |
656 | nexttbtt = intval; | 646 | else |
657 | else if (intval) | 647 | delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp)); |
658 | nexttbtt = roundup(nexttbtt, intval); | 648 | nexttbtt = tsf + roundup(delta, intval); |
659 | 649 | } | |
660 | tsf = ath9k_hw_gettsf64(ah); | ||
661 | tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE; | ||
662 | do { | ||
663 | nexttbtt += intval; | ||
664 | } while (nexttbtt < tsftu); | ||
665 | 650 | ||
666 | ath_dbg(common, ATH_DBG_BEACON, | 651 | ath_dbg(common, ATH_DBG_BEACON, |
667 | "IBSS nexttbtt %u intval %u (%u)\n", | 652 | "IBSS nexttbtt %u intval %u (%u)\n", |
@@ -672,7 +657,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, | |||
672 | * if we need to manually prepare beacon frames. Otherwise we use a | 657 | * if we need to manually prepare beacon frames. Otherwise we use a |
673 | * self-linked tx descriptor and let the hardware deal with things. | 658 | * self-linked tx descriptor and let the hardware deal with things. |
674 | */ | 659 | */ |
675 | intval |= ATH9K_BEACON_ENA; | ||
676 | ah->imask |= ATH9K_INT_SWBA; | 660 | ah->imask |= ATH9K_INT_SWBA; |
677 | 661 | ||
678 | ath_beaconq_config(sc); | 662 | ath_beaconq_config(sc); |