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 { ...@@ -385,6 +385,7 @@ struct ath_chanctx_sched {
bool wait_switch; bool wait_switch;
bool force_noa_update; bool force_noa_update;
bool extend_absence; bool extend_absence;
bool mgd_prepare_tx;
enum ath_chanctx_state state; enum ath_chanctx_state state;
u8 beacon_miss; u8 beacon_miss;
...@@ -977,6 +978,7 @@ struct ath_softc { ...@@ -977,6 +978,7 @@ struct ath_softc {
struct ath_chanctx_sched sched; struct ath_chanctx_sched sched;
struct ath_offchannel offchannel; struct ath_offchannel offchannel;
struct ath_chanctx *next_chan; struct ath_chanctx *next_chan;
struct completion go_beacon;
#endif #endif
unsigned long driver_data; unsigned long driver_data;
......
...@@ -421,6 +421,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ...@@ -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"); "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, * When a context becomes inactive, for example,
* disassociation of a station context, the NoA * disassociation of a station context, the NoA
...@@ -547,6 +550,15 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ...@@ -547,6 +550,15 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
} }
sc->sched.beacon_pending = false; 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) if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
break; break;
...@@ -1263,6 +1275,8 @@ void ath9k_init_channel_context(struct ath_softc *sc) ...@@ -1263,6 +1275,8 @@ void ath9k_init_channel_context(struct ath_softc *sc)
(unsigned long)sc); (unsigned long)sc);
setup_timer(&sc->sched.timer, ath_chanctx_timer, setup_timer(&sc->sched.timer, ath_chanctx_timer,
(unsigned long)sc); (unsigned long)sc);
init_completion(&sc->go_beacon);
} }
void ath9k_deinit_channel_context(struct ath_softc *sc) void ath9k_deinit_channel_context(struct ath_softc *sc)
......
...@@ -2474,7 +2474,11 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw, ...@@ -2474,7 +2474,11 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (struct ath_vif *) vif->drv_priv; 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; bool changed = false;
u32 beacon_int;
if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
return; return;
...@@ -2485,19 +2489,46 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw, ...@@ -2485,19 +2489,46 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex); mutex_lock(&sc->mutex);
spin_lock_bh(&sc->chan_lock); spin_lock_bh(&sc->chan_lock);
if (sc->next_chan || (sc->cur_chan != avp->chanctx)) { if (sc->next_chan || (sc->cur_chan != avp->chanctx))
sc->next_chan = avp->chanctx;
changed = true; 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, ath_dbg(common, CHAN_CTX,
"%s: Set chanctx state to FORCE_ACTIVE, changed: %d\n", "%s: Set chanctx state to FORCE_ACTIVE for vif: %pM\n",
__func__, changed); __func__, vif->addr);
spin_lock_bh(&sc->chan_lock);
sc->next_chan = avp->chanctx;
sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE; sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
spin_unlock_bh(&sc->chan_lock); 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); 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