diff options
author | Felix Fietkau <nbd@openwrt.org> | 2014-06-11 06:48:08 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-06-19 15:49:19 -0400 |
commit | 58b57375285223badddebdf8d905a864c271b87d (patch) | |
tree | 38209c32c4f0a58dca0b2715165df6ca92de47a5 /drivers/net/wireless/ath/ath9k | |
parent | 8eab25108e374403f759dd7de01084a1f3ba6d68 (diff) |
ath9k: Adjust AP beacon tsf based on station context
In multi channel context (AP + STA case), adjust the TSF time of
the AP chanctx to keep its beacons at half beacon interval offset
relative to the STA chanctx.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/channel.c | 48 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 5 |
3 files changed, 55 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 02f30980c31a..a4646a076099 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -335,6 +335,7 @@ struct ath_chanctx { | |||
335 | struct ath9k_hw_cal_data caldata; | 335 | struct ath9k_hw_cal_data caldata; |
336 | struct timespec tsf_ts; | 336 | struct timespec tsf_ts; |
337 | u64 tsf_val; | 337 | u64 tsf_val; |
338 | u32 last_beacon; | ||
338 | 339 | ||
339 | u16 txpower; | 340 | u16 txpower; |
340 | bool offchannel; | 341 | bool offchannel; |
@@ -348,6 +349,7 @@ enum ath_chanctx_event { | |||
348 | ATH_CHANCTX_EVENT_BEACON_PREPARE, | 349 | ATH_CHANCTX_EVENT_BEACON_PREPARE, |
349 | ATH_CHANCTX_EVENT_BEACON_SENT, | 350 | ATH_CHANCTX_EVENT_BEACON_SENT, |
350 | ATH_CHANCTX_EVENT_TSF_TIMER, | 351 | ATH_CHANCTX_EVENT_TSF_TIMER, |
352 | ATH_CHANCTX_EVENT_BEACON_RECEIVED, | ||
351 | }; | 353 | }; |
352 | 354 | ||
353 | enum ath_chanctx_state { | 355 | enum ath_chanctx_state { |
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 4793de079f77..6ea806cc68fe 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c | |||
@@ -382,10 +382,51 @@ void ath_chanctx_offchan_switch(struct ath_softc *sc, | |||
382 | ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef); | 382 | ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef); |
383 | } | 383 | } |
384 | 384 | ||
385 | static struct ath_chanctx * | ||
386 | ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx) | ||
387 | { | ||
388 | int idx = ctx - &sc->chanctx[0]; | ||
389 | |||
390 | return &sc->chanctx[!idx]; | ||
391 | } | ||
392 | |||
393 | static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc) | ||
394 | { | ||
395 | struct ath_chanctx *prev, *cur; | ||
396 | struct timespec ts; | ||
397 | u32 cur_tsf, prev_tsf, beacon_int; | ||
398 | s32 offset; | ||
399 | |||
400 | beacon_int = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); | ||
401 | |||
402 | cur = sc->cur_chan; | ||
403 | prev = ath_chanctx_get_next(sc, cur); | ||
404 | |||
405 | getrawmonotonic(&ts); | ||
406 | cur_tsf = (u32) cur->tsf_val + | ||
407 | ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts); | ||
408 | |||
409 | prev_tsf = prev->last_beacon - (u32) prev->tsf_val + cur_tsf; | ||
410 | prev_tsf -= ath9k_hw_get_tsf_offset(&prev->tsf_ts, &ts); | ||
411 | |||
412 | /* Adjust the TSF time of the AP chanctx to keep its beacons | ||
413 | * at half beacon interval offset relative to the STA chanctx. | ||
414 | */ | ||
415 | offset = cur_tsf - prev_tsf; | ||
416 | |||
417 | /* Ignore stale data or spurious timestamps */ | ||
418 | if (offset < 0 || offset > 3 * beacon_int) | ||
419 | return; | ||
420 | |||
421 | offset = beacon_int / 2 - (offset % beacon_int); | ||
422 | prev->tsf_val += offset; | ||
423 | } | ||
424 | |||
385 | void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, | 425 | void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, |
386 | enum ath_chanctx_event ev) | 426 | enum ath_chanctx_event ev) |
387 | { | 427 | { |
388 | struct ath_hw *ah = sc->sc_ah; | 428 | struct ath_hw *ah = sc->sc_ah; |
429 | struct ath_common *common = ath9k_hw_common(ah); | ||
389 | struct ath_vif *avp = NULL; | 430 | struct ath_vif *avp = NULL; |
390 | u32 tsf_time; | 431 | u32 tsf_time; |
391 | bool noa_changed = false; | 432 | bool noa_changed = false; |
@@ -410,6 +451,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
410 | tsf_time = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); | 451 | tsf_time = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); |
411 | tsf_time = sc->sched.next_tbtt + tsf_time / 4; | 452 | tsf_time = sc->sched.next_tbtt + tsf_time / 4; |
412 | sc->sched.switch_start_time = tsf_time; | 453 | sc->sched.switch_start_time = tsf_time; |
454 | sc->cur_chan->last_beacon = sc->sched.next_tbtt; | ||
413 | 455 | ||
414 | if (sc->sched.offchannel_duration) { | 456 | if (sc->sched.offchannel_duration) { |
415 | noa_changed = true; | 457 | noa_changed = true; |
@@ -441,6 +483,12 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, | |||
441 | sc->sched.state = ATH_CHANCTX_STATE_SWITCH; | 483 | sc->sched.state = ATH_CHANCTX_STATE_SWITCH; |
442 | ieee80211_queue_work(sc->hw, &sc->chanctx_work); | 484 | ieee80211_queue_work(sc->hw, &sc->chanctx_work); |
443 | break; | 485 | break; |
486 | case ATH_CHANCTX_EVENT_BEACON_RECEIVED: | ||
487 | if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) | ||
488 | break; | ||
489 | |||
490 | ath_chanctx_adjust_tbtt_delta(sc); | ||
491 | break; | ||
444 | } | 492 | } |
445 | 493 | ||
446 | spin_unlock_bh(&sc->chan_lock); | 494 | spin_unlock_bh(&sc->chan_lock); |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 7b9c7e53caaa..74ab1d02013b 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -892,6 +892,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, | |||
892 | return -EINVAL; | 892 | return -EINVAL; |
893 | } | 893 | } |
894 | 894 | ||
895 | if (rx_stats->is_mybeacon) { | ||
896 | sc->sched.next_tbtt = rx_stats->rs_tstamp; | ||
897 | ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_BEACON_RECEIVED); | ||
898 | } | ||
899 | |||
895 | ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); | 900 | ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); |
896 | 901 | ||
897 | rx_status->band = ah->curchan->chan->band; | 902 | rx_status->band = ah->curchan->chan->band; |