aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/beacon.c
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2011-03-22 16:54:17 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-03-30 14:15:17 -0400
commitdd347f2fb2ddb20a80e9a8285252bf208ab91398 (patch)
tree9e1a33ea4f50dd9b116e80da2fd6250d570eb001 /drivers/net/wireless/ath/ath9k/beacon.c
parentf39de992540cf68cc865498242f963f70f7e97b3 (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.c78
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*/
63static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, 63static 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);