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

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

ath9k: Check for active GO in mgd_prepare_tx()



If a GO interface is active when we receive a
mgd_prepare_tx() call, then we need to send
out a new NoA before switching to a new context.

Signed-off-by: default avatarSujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 26103b8d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -385,6 +385,7 @@ struct ath_chanctx_sched {
	bool wait_switch;
	bool force_noa_update;
	bool extend_absence;
	bool mgd_prepare_tx;
	enum ath_chanctx_state state;
	u8 beacon_miss;

@@ -977,6 +978,7 @@ struct ath_softc {
	struct ath_chanctx_sched sched;
	struct ath_offchannel offchannel;
	struct ath_chanctx *next_chan;
	struct completion go_beacon;
#endif

	unsigned long driver_data;
+14 −0
Original line number Diff line number Diff line
@@ -421,6 +421,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
				"Move chanctx state from WAIT_FOR_TIMER to WAIT_FOR_BEACON\n");
		}

		if (sc->sched.mgd_prepare_tx)
			sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;

		/*
		 * When a context becomes inactive, for example,
		 * disassociation of a station context, the NoA
@@ -547,6 +550,15 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
		}

		sc->sched.beacon_pending = false;

		if (sc->sched.mgd_prepare_tx) {
			sc->sched.mgd_prepare_tx = false;
			complete(&sc->go_beacon);
			ath_dbg(common, CHAN_CTX,
				"Beacon sent, complete go_beacon\n");
			break;
		}

		if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
			break;

@@ -1263,6 +1275,8 @@ void ath9k_init_channel_context(struct ath_softc *sc)
		    (unsigned long)sc);
	setup_timer(&sc->sched.timer, ath_chanctx_timer,
		    (unsigned long)sc);

	init_completion(&sc->go_beacon);
}

void ath9k_deinit_channel_context(struct ath_softc *sc)
+38 −7
Original line number Diff line number Diff line
@@ -2474,7 +2474,11 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
	struct ath_softc *sc = hw->priv;
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
	struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
	struct ath_beacon_config *cur_conf;
	struct ath_chanctx *go_ctx;
	unsigned long timeout;
	bool changed = false;
	u32 beacon_int;

	if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
		return;
@@ -2485,19 +2489,46 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
	mutex_lock(&sc->mutex);

	spin_lock_bh(&sc->chan_lock);
	if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
		sc->next_chan = avp->chanctx;
	if (sc->next_chan || (sc->cur_chan != avp->chanctx))
		changed = true;
	spin_unlock_bh(&sc->chan_lock);

	if (!changed)
		goto out;

	go_ctx = ath_is_go_chanctx_present(sc);

	if (go_ctx) {
		/*
		 * Wait till the GO interface gets a chance
		 * to send out an NoA.
		 */
		spin_lock_bh(&sc->chan_lock);
		sc->sched.mgd_prepare_tx = true;
		cur_conf = &go_ctx->beacon;
		beacon_int = TU_TO_USEC(cur_conf->beacon_interval);
		spin_unlock_bh(&sc->chan_lock);

		timeout = usecs_to_jiffies(beacon_int);
		init_completion(&sc->go_beacon);

		if (wait_for_completion_timeout(&sc->go_beacon,
						timeout) == 0)
			ath_dbg(common, CHAN_CTX,
				"Failed to send new NoA\n");
	}

	ath_dbg(common, CHAN_CTX,
		"%s: Set chanctx state to FORCE_ACTIVE, changed: %d\n",
		__func__, changed);
		"%s: Set chanctx state to FORCE_ACTIVE for vif: %pM\n",
		__func__, vif->addr);

	spin_lock_bh(&sc->chan_lock);
	sc->next_chan = avp->chanctx;
	sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
	spin_unlock_bh(&sc->chan_lock);

	if (changed)
	ath_chanctx_set_next(sc, true);

out:
	mutex_unlock(&sc->mutex);
}