diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/channel.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/channel.c | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 1cb2909a114c..3d9776c4c909 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c | |||
@@ -474,6 +474,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
474 | { | 474 | { |
475 | struct ath_hw *ah = sc->sc_ah; | 475 | struct ath_hw *ah = sc->sc_ah; |
476 | struct ath_common *common = ath9k_hw_common(ah); | 476 | struct ath_common *common = ath9k_hw_common(ah); |
477 | struct ath_beacon_config *cur_conf; | ||
477 | struct ath_vif *avp = NULL; | 478 | struct ath_vif *avp = NULL; |
478 | struct ath_chanctx *ctx; | 479 | struct ath_chanctx *ctx; |
479 | u32 tsf_time; | 480 | u32 tsf_time; |
@@ -514,12 +515,29 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
514 | sc->sched.beacon_pending = true; | 515 | sc->sched.beacon_pending = true; |
515 | sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER); | 516 | sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER); |
516 | 517 | ||
518 | cur_conf = &sc->cur_chan->beacon; | ||
517 | /* defer channel switch by a quarter beacon interval */ | 519 | /* defer channel switch by a quarter beacon interval */ |
518 | tsf_time = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); | 520 | tsf_time = TU_TO_USEC(cur_conf->beacon_interval); |
519 | tsf_time = sc->sched.next_tbtt + tsf_time / 4; | 521 | tsf_time = sc->sched.next_tbtt + tsf_time / 4; |
520 | sc->sched.switch_start_time = tsf_time; | 522 | sc->sched.switch_start_time = tsf_time; |
521 | sc->cur_chan->last_beacon = sc->sched.next_tbtt; | 523 | sc->cur_chan->last_beacon = sc->sched.next_tbtt; |
522 | 524 | ||
525 | /* Prevent wrap-around issues */ | ||
526 | if (avp->periodic_noa_duration && | ||
527 | tsf_time - avp->periodic_noa_start > BIT(30)) | ||
528 | avp->periodic_noa_duration = 0; | ||
529 | |||
530 | if (ctx->active && !avp->periodic_noa_duration) { | ||
531 | avp->periodic_noa_start = tsf_time; | ||
532 | avp->periodic_noa_duration = | ||
533 | TU_TO_USEC(cur_conf->beacon_interval) / 2 - | ||
534 | sc->sched.channel_switch_time; | ||
535 | noa_changed = true; | ||
536 | } else if (!ctx->active && avp->periodic_noa_duration) { | ||
537 | avp->periodic_noa_duration = 0; | ||
538 | noa_changed = true; | ||
539 | } | ||
540 | |||
523 | if (sc->sched.offchannel_duration) { | 541 | if (sc->sched.offchannel_duration) { |
524 | noa_changed = true; | 542 | noa_changed = true; |
525 | avp->offchannel_start = tsf_time; | 543 | avp->offchannel_start = tsf_time; |
@@ -575,11 +593,11 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
575 | * beacon period (minus channel switch time) | 593 | * beacon period (minus channel switch time) |
576 | */ | 594 | */ |
577 | sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan); | 595 | sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan); |
596 | cur_conf = &sc->cur_chan->beacon; | ||
578 | 597 | ||
579 | sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; | 598 | sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; |
580 | tsf_time = ath9k_hw_gettsf32(sc->sc_ah); | 599 | tsf_time = ath9k_hw_gettsf32(sc->sc_ah); |
581 | tsf_time += | 600 | tsf_time += TU_TO_USEC(cur_conf->beacon_interval) / 2; |
582 | TU_TO_USEC(sc->cur_chan->beacon.beacon_interval) / 2; | ||
583 | tsf_time -= sc->sched.channel_switch_time; | 601 | tsf_time -= sc->sched.channel_switch_time; |
584 | sc->sched.switch_start_time = tsf_time; | 602 | sc->sched.switch_start_time = tsf_time; |
585 | 603 | ||