summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/ath9k/channel.c
diff options
context:
space:
mode:
authorSujith Manoharan <c_manoha@qca.qualcomm.com>2014-09-10 13:45:57 (GMT)
committerJohn W. Linville <linville@tuxdriver.com>2014-09-11 19:27:39 (GMT)
commitd0975edd59b94d8906008cf3c68020a44cc198c5 (patch)
tree5b5df03a5bcd0323b89a12742d66b1852df27d2f /drivers/net/wireless/ath/ath9k/channel.c
parentcbc775db2e17cc24a9d3b2f14570ec7c1e0923af (diff)
downloadlinux-d0975edd59b94d8906008cf3c68020a44cc198c5.tar.xz
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: Sujith Manoharan <c_manoha@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/channel.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/channel.c105
1 files changed, 70 insertions, 35 deletions
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index ae575cb..ab3d29d 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -310,7 +310,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
struct ath_chanctx *ctx;
u32 tsf_time;
u32 beacon_int;
- bool noa_changed = false;
if (vif)
avp = (struct ath_vif *) vif->drv_priv;
@@ -372,22 +371,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
sc->sched.switch_start_time = tsf_time;
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
* chanctx, stay on the STA channel for one extra beacon period,
* to resync the timer properly.
@@ -395,21 +378,65 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
if (ctx->active && sc->sched.beacon_miss >= 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_duration =
- sc->sched.offchannel_duration;
+ avp->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_start = tsf_time;
+ avp->noa_duration =
+ TU_TO_USEC(cur_conf->beacon_interval) / 2 -
+ sc->sched.channel_switch_time;
- ath_dbg(common, CHAN_CTX,
- "periodic_noa_duration: %d, periodic_noa_start: %d, noa_index: %d\n",
- avp->periodic_noa_duration,
- avp->periodic_noa_start,
- avp->noa_index);
+ if (test_bit(ATH_OP_SCANNING, &common->op_flags))
+ avp->periodic_noa = false;
+ else
+ avp->periodic_noa = true;
+
+ 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;
case ATH_CHANCTX_EVENT_BEACON_SENT:
@@ -736,6 +763,10 @@ void ath_scan_complete(struct ath_softc *sc, bool abort)
sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
ieee80211_scan_completed(sc->hw, abort);
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);
ath9k_ps_restore(sc);
}
@@ -1218,10 +1249,10 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
int noa_len, noa_desc, i = 0;
u8 *hdr;
- if (!avp->offchannel_duration && !avp->periodic_noa_duration)
+ if (!avp->offchannel_duration && !avp->noa_duration)
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;
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,
noa->index = avp->noa_index;
noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp);
- if (avp->periodic_noa_duration) {
- u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
+ if (avp->noa_duration) {
+ 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->periodic_noa_start);
- noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration);
- noa->desc[i].interval = cpu_to_le32(interval);
+ noa->desc[i].start_time = cpu_to_le32(avp->noa_start);
+ noa->desc[i].duration = cpu_to_le32(avp->noa_duration);
i++;
}