Commit d0975edd authored by Sujith Manoharan's avatar Sujith Manoharan Committed by John W. Linville

ath9k: Fix Notice of Absence issues

* The index has to incremented only when advertising
  a new NoA schedule.

* Switch to non-periodic NoA when starting a scan operation
  and multiple channel contexts are active.

* Make sure that periodic NoA is advertised again when
  scan ends. Since the offchannel timer moves the offchannel
  state to IDLE after the GO operating channel becomes
  active, use a flag "force_noa_update" to update the
  NoA contents.
Signed-off-by: default avatarSujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent cbc775db
...@@ -379,6 +379,7 @@ struct ath_chanctx_sched { ...@@ -379,6 +379,7 @@ struct ath_chanctx_sched {
bool beacon_pending; bool beacon_pending;
bool offchannel_pending; bool offchannel_pending;
bool wait_switch; bool wait_switch;
bool force_noa_update;
enum ath_chanctx_state state; enum ath_chanctx_state state;
u8 beacon_miss; u8 beacon_miss;
...@@ -595,8 +596,10 @@ struct ath_vif { ...@@ -595,8 +596,10 @@ struct ath_vif {
u32 offchannel_start; u32 offchannel_start;
u32 offchannel_duration; u32 offchannel_duration;
u32 periodic_noa_start; /* These are used for both periodic and one-shot */
u32 periodic_noa_duration; u32 noa_start;
u32 noa_duration;
bool periodic_noa;
}; };
struct ath9k_vif_iter_data { struct ath9k_vif_iter_data {
......
...@@ -310,7 +310,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ...@@ -310,7 +310,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
struct ath_chanctx *ctx; struct ath_chanctx *ctx;
u32 tsf_time; u32 tsf_time;
u32 beacon_int; u32 beacon_int;
bool noa_changed = false;
if (vif) if (vif)
avp = (struct ath_vif *) vif->drv_priv; avp = (struct ath_vif *) vif->drv_priv;
...@@ -372,22 +371,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ...@@ -372,22 +371,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
sc->sched.switch_start_time = tsf_time; sc->sched.switch_start_time = tsf_time;
sc->cur_chan->last_beacon = sc->sched.next_tbtt; sc->cur_chan->last_beacon = sc->sched.next_tbtt;
/* Prevent wrap-around issues */
if (avp->periodic_noa_duration &&
tsf_time - avp->periodic_noa_start > BIT(30))
avp->periodic_noa_duration = 0;
if (ctx->active) {
avp->periodic_noa_start = tsf_time;
avp->periodic_noa_duration =
TU_TO_USEC(cur_conf->beacon_interval) / 2 -
sc->sched.channel_switch_time;
noa_changed = true;
} else if (!ctx->active) {
avp->periodic_noa_duration = 0;
noa_changed = true;
}
/* If at least two consecutive beacons were missed on the STA /* If at least two consecutive beacons were missed on the STA
* chanctx, stay on the STA channel for one extra beacon period, * chanctx, stay on the STA channel for one extra beacon period,
* to resync the timer properly. * to resync the timer properly.
...@@ -395,21 +378,65 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ...@@ -395,21 +378,65 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
if (ctx->active && sc->sched.beacon_miss >= 2) if (ctx->active && sc->sched.beacon_miss >= 2)
sc->sched.offchannel_duration = 3 * beacon_int / 2; sc->sched.offchannel_duration = 3 * beacon_int / 2;
if (sc->sched.offchannel_duration) { /*
noa_changed = true; * If an offchannel switch is scheduled to happen after
* a beacon transmission, update the NoA with one-shot
* values and increment the index.
*/
if (sc->next_chan == &sc->offchannel.chan) {
avp->noa_index++;
avp->offchannel_start = tsf_time; avp->offchannel_start = tsf_time;
avp->offchannel_duration = avp->offchannel_duration = sc->sched.offchannel_duration;
sc->sched.offchannel_duration;
ath_dbg(common, CHAN_CTX,
"offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
avp->offchannel_duration,
avp->offchannel_start,
avp->noa_index);
/*
* When multiple contexts are active, the NoA
* has to be recalculated and advertised after
* an offchannel operation.
*/
if (ctx->active && avp->noa_duration)
avp->noa_duration = 0;
break;
} }
if (noa_changed) /* Prevent wrap-around issues */
if (avp->noa_duration && tsf_time - avp->noa_start > BIT(30))
avp->noa_duration = 0;
/*
* If multiple contexts are active, start periodic
* NoA and increment the index for the first
* announcement.
*/
if (ctx->active &&
(!avp->noa_duration || sc->sched.force_noa_update)) {
avp->noa_index++; avp->noa_index++;
avp->noa_start = tsf_time;
avp->noa_duration =
TU_TO_USEC(cur_conf->beacon_interval) / 2 -
sc->sched.channel_switch_time;
ath_dbg(common, CHAN_CTX, if (test_bit(ATH_OP_SCANNING, &common->op_flags))
"periodic_noa_duration: %d, periodic_noa_start: %d, noa_index: %d\n", avp->periodic_noa = false;
avp->periodic_noa_duration, else
avp->periodic_noa_start, avp->periodic_noa = true;
avp->noa_index);
ath_dbg(common, CHAN_CTX,
"noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
avp->noa_duration,
avp->noa_start,
avp->noa_index,
avp->periodic_noa);
}
if (ctx->active && sc->sched.force_noa_update)
sc->sched.force_noa_update = false;
break; break;
case ATH_CHANCTX_EVENT_BEACON_SENT: case ATH_CHANCTX_EVENT_BEACON_SENT:
...@@ -736,6 +763,10 @@ void ath_scan_complete(struct ath_softc *sc, bool abort) ...@@ -736,6 +763,10 @@ void ath_scan_complete(struct ath_softc *sc, bool abort)
sc->offchannel.state = ATH_OFFCHANNEL_IDLE; sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
ieee80211_scan_completed(sc->hw, abort); ieee80211_scan_completed(sc->hw, abort);
clear_bit(ATH_OP_SCANNING, &common->op_flags); clear_bit(ATH_OP_SCANNING, &common->op_flags);
spin_lock_bh(&sc->chan_lock);
if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
sc->sched.force_noa_update = true;
spin_unlock_bh(&sc->chan_lock);
ath_offchannel_next(sc); ath_offchannel_next(sc);
ath9k_ps_restore(sc); ath9k_ps_restore(sc);
} }
...@@ -1218,10 +1249,10 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, ...@@ -1218,10 +1249,10 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
int noa_len, noa_desc, i = 0; int noa_len, noa_desc, i = 0;
u8 *hdr; u8 *hdr;
if (!avp->offchannel_duration && !avp->periodic_noa_duration) if (!avp->offchannel_duration && !avp->noa_duration)
return; return;
noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration; noa_desc = !!avp->offchannel_duration + !!avp->noa_duration;
noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc; noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc;
hdr = skb_put(skb, sizeof(noa_ie_hdr)); hdr = skb_put(skb, sizeof(noa_ie_hdr));
...@@ -1235,13 +1266,17 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, ...@@ -1235,13 +1266,17 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
noa->index = avp->noa_index; noa->index = avp->noa_index;
noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp); noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp);
if (avp->periodic_noa_duration) { if (avp->noa_duration) {
u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); if (avp->periodic_noa) {
u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
noa->desc[i].count = 255;
noa->desc[i].interval = cpu_to_le32(interval);
} else {
noa->desc[i].count = 1;
}
noa->desc[i].count = 255; noa->desc[i].start_time = cpu_to_le32(avp->noa_start);
noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start); noa->desc[i].duration = cpu_to_le32(avp->noa_duration);
noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration);
noa->desc[i].interval = cpu_to_le32(interval);
i++; i++;
} }
......
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