aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2014-06-11 06:48:08 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-06-19 15:49:19 -0400
commit58b57375285223badddebdf8d905a864c271b87d (patch)
tree38209c32c4f0a58dca0b2715165df6ca92de47a5 /drivers/net/wireless/ath/ath9k
parent8eab25108e374403f759dd7de01084a1f3ba6d68 (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.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/channel.c48
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c5
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
353enum ath_chanctx_state { 355enum 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
385static struct ath_chanctx *
386ath_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
393static 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
385void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, 425void 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;