ath9k: disable beaconing before stopping beacon queue

Beaconing should be disabled before stopping beacon queue.
Not doing so could queue up beacons in hw that causes
failure to stop Tx DMA, due to pending frames in hw
and also unnecessary beacon tasklet schedule.

Signed-off-by: Rajkumar Manoharan <rmanoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Rajkumar Manoharan 2011-02-09 17:46:39 +05:30 committed by John W. Linville
parent d76dfc612b
commit 014cf3bb1e
3 changed files with 52 additions and 22 deletions

View file

@ -348,6 +348,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
struct ath_vif {
int av_bslot;
bool is_bslot_active;
__le64 tsf_adjust; /* TSF adjustment for staggered beacons */
enum nl80211_iftype av_opmode;
struct ath_buf *av_bcbuf;
@ -402,6 +403,7 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
int ath_beaconq_config(struct ath_softc *sc);
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
/*******/
/* ANI */

View file

@ -143,7 +143,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
avp = (void *)vif->drv_priv;
cabq = sc->beacon.cabq;
if (avp->av_bcbuf == NULL)
if ((avp->av_bcbuf == NULL) || !avp->is_bslot_active)
return NULL;
/* Release the old beacon first */
@ -249,6 +249,7 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif)
for (slot = 0; slot < ATH_BCBUF; slot++)
if (sc->beacon.bslot[slot] == NULL) {
avp->av_bslot = slot;
avp->is_bslot_active = false;
/* NB: keep looking for a double slot */
if (slot == 0 || !sc->beacon.bslot[slot-1])
@ -315,6 +316,7 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif)
ath_err(common, "dma_mapping_error on beacon alloc\n");
return -ENOMEM;
}
avp->is_bslot_active = true;
return 0;
}
@ -749,3 +751,36 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
sc->sc_flags |= SC_OP_BEACONS;
}
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_vif *avp;
int slot;
bool found = false;
ath9k_ps_wakeup(sc);
if (status) {
for (slot = 0; slot < ATH_BCBUF; slot++) {
if (sc->beacon.bslot[slot]) {
avp = (void *)sc->beacon.bslot[slot]->drv_priv;
if (avp->is_bslot_active) {
found = true;
break;
}
}
}
if (found) {
/* Re-enable beaconing */
ah->imask |= ATH9K_INT_SWBA;
ath9k_hw_set_interrupts(ah, ah->imask);
}
} else {
/* Disable SWBA interrupt */
ah->imask &= ~ATH9K_INT_SWBA;
ath9k_hw_set_interrupts(ah, ah->imask);
tasklet_kill(&sc->bcon_tasklet);
ath9k_hw_stoptxdma(ah, sc->beacon.beaconq);
}
ath9k_ps_restore(sc);
}

View file

@ -1293,24 +1293,10 @@ static void ath9k_reclaim_beacon(struct ath_softc *sc,
{
struct ath_vif *avp = (void *)vif->drv_priv;
/* Disable SWBA interrupt */
sc->sc_ah->imask &= ~ATH9K_INT_SWBA;
ath9k_ps_wakeup(sc);
ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
tasklet_kill(&sc->bcon_tasklet);
ath9k_ps_restore(sc);
ath9k_set_beaconing_status(sc, false);
ath_beacon_return(sc, avp);
ath9k_set_beaconing_status(sc, true);
sc->sc_flags &= ~SC_OP_BEACONS;
if (sc->nbcnvifs > 0) {
/* Re-enable beaconing */
sc->sc_ah->imask |= ATH9K_INT_SWBA;
ath9k_ps_wakeup(sc);
ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
ath9k_ps_restore(sc);
}
}
static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
@ -1438,16 +1424,17 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
if (ath9k_uses_beacons(vif->type)) {
int error;
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
/* This may fail because upper levels do not have beacons
* properly configured yet. That's OK, we assume it
* will be properly configured and then we will be notified
* in the info_changed method and set up beacons properly
* there.
*/
ath9k_set_beaconing_status(sc, false);
error = ath_beacon_alloc(sc, vif);
if (!error)
ath_beacon_config(sc, vif);
ath9k_set_beaconing_status(sc, true);
}
}
@ -1920,10 +1907,11 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
/* Enable transmission of beacons (AP, IBSS, MESH) */
if ((changed & BSS_CHANGED_BEACON) ||
((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) {
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
ath9k_set_beaconing_status(sc, false);
error = ath_beacon_alloc(sc, vif);
if (!error)
ath_beacon_config(sc, vif);
ath9k_set_beaconing_status(sc, true);
}
if (changed & BSS_CHANGED_ERP_SLOT) {
@ -1946,8 +1934,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
/* Disable transmission of beacons */
if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon)
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
!bss_conf->enable_beacon) {
ath9k_set_beaconing_status(sc, false);
avp->is_bslot_active = false;
ath9k_set_beaconing_status(sc, true);
}
if (changed & BSS_CHANGED_BEACON_INT) {
cur_conf->beacon_interval = bss_conf->beacon_int;
@ -1957,10 +1949,11 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
*/
if (vif->type == NL80211_IFTYPE_AP) {
sc->sc_flags |= SC_OP_TSF_RESET;
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
ath9k_set_beaconing_status(sc, false);
error = ath_beacon_alloc(sc, vif);
if (!error)
ath_beacon_config(sc, vif);
ath9k_set_beaconing_status(sc, true);
} else {
ath_beacon_config(sc, vif);
}