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

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
......@@ -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;
......
......@@ -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)
......
......@@ -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);
ath_chanctx_set_next(sc, true);
out:
mutex_unlock(&sc->mutex);
}
......
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