Commit 58b57375 authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville

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: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarRajkumar Manoharan <rmanohar@qti.qualcomm.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 8eab2510
...@@ -335,6 +335,7 @@ struct ath_chanctx { ...@@ -335,6 +335,7 @@ struct ath_chanctx {
struct ath9k_hw_cal_data caldata; struct ath9k_hw_cal_data caldata;
struct timespec tsf_ts; struct timespec tsf_ts;
u64 tsf_val; u64 tsf_val;
u32 last_beacon;
u16 txpower; u16 txpower;
bool offchannel; bool offchannel;
...@@ -348,6 +349,7 @@ enum ath_chanctx_event { ...@@ -348,6 +349,7 @@ enum ath_chanctx_event {
ATH_CHANCTX_EVENT_BEACON_PREPARE, ATH_CHANCTX_EVENT_BEACON_PREPARE,
ATH_CHANCTX_EVENT_BEACON_SENT, ATH_CHANCTX_EVENT_BEACON_SENT,
ATH_CHANCTX_EVENT_TSF_TIMER, ATH_CHANCTX_EVENT_TSF_TIMER,
ATH_CHANCTX_EVENT_BEACON_RECEIVED,
}; };
enum ath_chanctx_state { enum ath_chanctx_state {
......
...@@ -382,10 +382,51 @@ void ath_chanctx_offchan_switch(struct ath_softc *sc, ...@@ -382,10 +382,51 @@ void ath_chanctx_offchan_switch(struct ath_softc *sc,
ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef); ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef);
} }
static struct ath_chanctx *
ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx)
{
int idx = ctx - &sc->chanctx[0];
return &sc->chanctx[!idx];
}
static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc)
{
struct ath_chanctx *prev, *cur;
struct timespec ts;
u32 cur_tsf, prev_tsf, beacon_int;
s32 offset;
beacon_int = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
cur = sc->cur_chan;
prev = ath_chanctx_get_next(sc, cur);
getrawmonotonic(&ts);
cur_tsf = (u32) cur->tsf_val +
ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts);
prev_tsf = prev->last_beacon - (u32) prev->tsf_val + cur_tsf;
prev_tsf -= ath9k_hw_get_tsf_offset(&prev->tsf_ts, &ts);
/* Adjust the TSF time of the AP chanctx to keep its beacons
* at half beacon interval offset relative to the STA chanctx.
*/
offset = cur_tsf - prev_tsf;
/* Ignore stale data or spurious timestamps */
if (offset < 0 || offset > 3 * beacon_int)
return;
offset = beacon_int / 2 - (offset % beacon_int);
prev->tsf_val += offset;
}
void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
enum ath_chanctx_event ev) enum ath_chanctx_event ev)
{ {
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = NULL; struct ath_vif *avp = NULL;
u32 tsf_time; u32 tsf_time;
bool noa_changed = false; bool noa_changed = false;
...@@ -410,6 +451,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ...@@ -410,6 +451,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
tsf_time = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); tsf_time = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
tsf_time = sc->sched.next_tbtt + tsf_time / 4; tsf_time = sc->sched.next_tbtt + tsf_time / 4;
sc->sched.switch_start_time = tsf_time; sc->sched.switch_start_time = tsf_time;
sc->cur_chan->last_beacon = sc->sched.next_tbtt;
if (sc->sched.offchannel_duration) { if (sc->sched.offchannel_duration) {
noa_changed = true; noa_changed = true;
...@@ -441,6 +483,12 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ...@@ -441,6 +483,12 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
sc->sched.state = ATH_CHANCTX_STATE_SWITCH; sc->sched.state = ATH_CHANCTX_STATE_SWITCH;
ieee80211_queue_work(sc->hw, &sc->chanctx_work); ieee80211_queue_work(sc->hw, &sc->chanctx_work);
break; break;
case ATH_CHANCTX_EVENT_BEACON_RECEIVED:
if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
break;
ath_chanctx_adjust_tbtt_delta(sc);
break;
} }
spin_unlock_bh(&sc->chan_lock); spin_unlock_bh(&sc->chan_lock);
......
...@@ -892,6 +892,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, ...@@ -892,6 +892,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
return -EINVAL; return -EINVAL;
} }
if (rx_stats->is_mybeacon) {
sc->sched.next_tbtt = rx_stats->rs_tstamp;
ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_BEACON_RECEIVED);
}
ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status);
rx_status->band = ah->curchan->chan->band; rx_status->band = ah->curchan->chan->band;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment