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:
parent
d76dfc612b
commit
014cf3bb1e
|
@ -348,6 +348,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
|
||||||
|
|
||||||
struct ath_vif {
|
struct ath_vif {
|
||||||
int av_bslot;
|
int av_bslot;
|
||||||
|
bool is_bslot_active;
|
||||||
__le64 tsf_adjust; /* TSF adjustment for staggered beacons */
|
__le64 tsf_adjust; /* TSF adjustment for staggered beacons */
|
||||||
enum nl80211_iftype av_opmode;
|
enum nl80211_iftype av_opmode;
|
||||||
struct ath_buf *av_bcbuf;
|
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);
|
int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif);
|
||||||
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
|
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
|
||||||
int ath_beaconq_config(struct ath_softc *sc);
|
int ath_beaconq_config(struct ath_softc *sc);
|
||||||
|
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
|
||||||
|
|
||||||
/*******/
|
/*******/
|
||||||
/* ANI */
|
/* ANI */
|
||||||
|
|
|
@ -143,7 +143,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
|
||||||
avp = (void *)vif->drv_priv;
|
avp = (void *)vif->drv_priv;
|
||||||
cabq = sc->beacon.cabq;
|
cabq = sc->beacon.cabq;
|
||||||
|
|
||||||
if (avp->av_bcbuf == NULL)
|
if ((avp->av_bcbuf == NULL) || !avp->is_bslot_active)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Release the old beacon first */
|
/* 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++)
|
for (slot = 0; slot < ATH_BCBUF; slot++)
|
||||||
if (sc->beacon.bslot[slot] == NULL) {
|
if (sc->beacon.bslot[slot] == NULL) {
|
||||||
avp->av_bslot = slot;
|
avp->av_bslot = slot;
|
||||||
|
avp->is_bslot_active = false;
|
||||||
|
|
||||||
/* NB: keep looking for a double slot */
|
/* NB: keep looking for a double slot */
|
||||||
if (slot == 0 || !sc->beacon.bslot[slot-1])
|
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");
|
ath_err(common, "dma_mapping_error on beacon alloc\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
avp->is_bslot_active = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -749,3 +751,36 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||||
|
|
||||||
sc->sc_flags |= SC_OP_BEACONS;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -1293,24 +1293,10 @@ static void ath9k_reclaim_beacon(struct ath_softc *sc,
|
||||||
{
|
{
|
||||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||||
|
|
||||||
/* Disable SWBA interrupt */
|
ath9k_set_beaconing_status(sc, false);
|
||||||
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);
|
|
||||||
|
|
||||||
ath_beacon_return(sc, avp);
|
ath_beacon_return(sc, avp);
|
||||||
|
ath9k_set_beaconing_status(sc, true);
|
||||||
sc->sc_flags &= ~SC_OP_BEACONS;
|
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)
|
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)) {
|
if (ath9k_uses_beacons(vif->type)) {
|
||||||
int error;
|
int error;
|
||||||
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
|
||||||
/* This may fail because upper levels do not have beacons
|
/* This may fail because upper levels do not have beacons
|
||||||
* properly configured yet. That's OK, we assume it
|
* properly configured yet. That's OK, we assume it
|
||||||
* will be properly configured and then we will be notified
|
* will be properly configured and then we will be notified
|
||||||
* in the info_changed method and set up beacons properly
|
* in the info_changed method and set up beacons properly
|
||||||
* there.
|
* there.
|
||||||
*/
|
*/
|
||||||
|
ath9k_set_beaconing_status(sc, false);
|
||||||
error = ath_beacon_alloc(sc, vif);
|
error = ath_beacon_alloc(sc, vif);
|
||||||
if (!error)
|
if (!error)
|
||||||
ath_beacon_config(sc, vif);
|
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) */
|
/* Enable transmission of beacons (AP, IBSS, MESH) */
|
||||||
if ((changed & BSS_CHANGED_BEACON) ||
|
if ((changed & BSS_CHANGED_BEACON) ||
|
||||||
((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_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);
|
error = ath_beacon_alloc(sc, vif);
|
||||||
if (!error)
|
if (!error)
|
||||||
ath_beacon_config(sc, vif);
|
ath_beacon_config(sc, vif);
|
||||||
|
ath9k_set_beaconing_status(sc, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed & BSS_CHANGED_ERP_SLOT) {
|
if (changed & BSS_CHANGED_ERP_SLOT) {
|
||||||
|
@ -1946,8 +1934,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable transmission of beacons */
|
/* Disable transmission of beacons */
|
||||||
if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon)
|
if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
|
||||||
ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
|
!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) {
|
if (changed & BSS_CHANGED_BEACON_INT) {
|
||||||
cur_conf->beacon_interval = bss_conf->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) {
|
if (vif->type == NL80211_IFTYPE_AP) {
|
||||||
sc->sc_flags |= SC_OP_TSF_RESET;
|
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);
|
error = ath_beacon_alloc(sc, vif);
|
||||||
if (!error)
|
if (!error)
|
||||||
ath_beacon_config(sc, vif);
|
ath_beacon_config(sc, vif);
|
||||||
|
ath9k_set_beaconing_status(sc, true);
|
||||||
} else {
|
} else {
|
||||||
ath_beacon_config(sc, vif);
|
ath_beacon_config(sc, vif);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue