Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -379,6 +379,7 @@ struct ath_chanctx_sched {
	bool beacon_pending;
	bool offchannel_pending;
	bool wait_switch;
	bool force_noa_update;
	enum ath_chanctx_state state;
	u8 beacon_miss;

@@ -595,8 +596,10 @@ struct ath_vif {
	u32 offchannel_start;
	u32 offchannel_duration;

	u32 periodic_noa_start;
	u32 periodic_noa_duration;
	/* These are used for both periodic and one-shot */
	u32 noa_start;
	u32 noa_duration;
	bool periodic_noa;
};

struct ath9k_vif_iter_data {
+70 −35
Original line number Diff line number Diff line
@@ -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;

			if (test_bit(ATH_OP_SCANNING, &common->op_flags))
				avp->periodic_noa = false;
			else
				avp->periodic_noa = true;

			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);
				"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) {
	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].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);
		} else {
			noa->desc[i].count = 1;
		}

		noa->desc[i].start_time = cpu_to_le32(avp->noa_start);
		noa->desc[i].duration = cpu_to_le32(avp->noa_duration);
		i++;
	}