ath9k: Cleanup beacon logic
* The beaconing status routine is not required, since in multi-VIF cases the HW beacon parameters should not be re-configured. * Remove SC_OP_TSF_RESET - when a beaconing interface comes up the first time, the TSF has to be reset. * Simplify ath9k_allow_beacon_config(). * Handle setting/clearing the SWBA interrupt properly. * Remove the TSF mangling in IBSS mode, it is not required. * General code cleanup. Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
6c43c090a9
commit
ef4ad63368
|
@ -389,6 +389,7 @@ struct ath_beacon_config {
|
|||
u16 dtim_period;
|
||||
u16 bmiss_timeout;
|
||||
u8 dtim_count;
|
||||
bool enable_beacon;
|
||||
};
|
||||
|
||||
struct ath_beacon {
|
||||
|
@ -415,11 +416,13 @@ struct ath_beacon {
|
|||
};
|
||||
|
||||
void ath_beacon_tasklet(unsigned long data);
|
||||
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
|
||||
bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
|
||||
void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
|
||||
u32 changed);
|
||||
void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
|
||||
void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
|
||||
int ath_beaconq_config(struct ath_softc *sc);
|
||||
void ath_set_beacon(struct ath_softc *sc);
|
||||
void ath9k_set_beacon(struct ath_softc *sc);
|
||||
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
|
||||
|
||||
/*******************/
|
||||
|
@ -622,7 +625,6 @@ enum sc_op_flags {
|
|||
SC_OP_INVALID,
|
||||
SC_OP_BEACONS,
|
||||
SC_OP_RXFLUSH,
|
||||
SC_OP_TSF_RESET,
|
||||
SC_OP_ANI_RUN,
|
||||
SC_OP_PRIM_STA_VIF,
|
||||
SC_OP_HW_RESET,
|
||||
|
|
|
@ -315,7 +315,6 @@ void ath_beacon_tasklet(unsigned long data)
|
|||
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
|
||||
ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
|
||||
sc->beacon.bmisscnt = 0;
|
||||
set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
||||
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
|
||||
}
|
||||
|
||||
|
@ -401,21 +400,16 @@ void ath_beacon_tasklet(unsigned long data)
|
|||
}
|
||||
}
|
||||
|
||||
static void ath9k_beacon_init(struct ath_softc *sc,
|
||||
u32 next_beacon,
|
||||
u32 beacon_period)
|
||||
static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval)
|
||||
{
|
||||
if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
|
||||
ath9k_ps_wakeup(sc);
|
||||
ath9k_hw_reset_tsf(sc->sc_ah);
|
||||
}
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
|
||||
|
||||
if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
|
||||
ath9k_ps_restore(sc);
|
||||
clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
||||
}
|
||||
ath9k_hw_disable_interrupts(ah);
|
||||
ath9k_hw_reset_tsf(ah);
|
||||
ath9k_hw_beaconinit(ah, nexttbtt, intval);
|
||||
sc->beacon.bmisscnt = 0;
|
||||
ath9k_hw_set_interrupts(ah);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -423,32 +417,28 @@ static void ath9k_beacon_init(struct ath_softc *sc,
|
|||
* burst together. For the former arrange for the SWBA to be delivered for each
|
||||
* slot. Slots that are not occupied will generate nothing.
|
||||
*/
|
||||
static void ath_beacon_config_ap(struct ath_softc *sc,
|
||||
struct ath_beacon_config *conf)
|
||||
static void ath9k_beacon_config_ap(struct ath_softc *sc,
|
||||
struct ath_beacon_config *conf)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
u32 nexttbtt, intval;
|
||||
|
||||
/* NB: the beacon interval is kept internally in TU's */
|
||||
intval = TU_TO_USEC(conf->beacon_interval);
|
||||
intval /= ATH_BCBUF; /* for staggered beacons */
|
||||
intval /= ATH_BCBUF;
|
||||
nexttbtt = intval;
|
||||
|
||||
/*
|
||||
* In AP mode we enable the beacon timers and SWBA interrupts to
|
||||
* prepare beacon frames.
|
||||
*/
|
||||
ah->imask |= ATH9K_INT_SWBA;
|
||||
if (conf->enable_beacon)
|
||||
ah->imask |= ATH9K_INT_SWBA;
|
||||
else
|
||||
ah->imask &= ~ATH9K_INT_SWBA;
|
||||
|
||||
ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n",
|
||||
nexttbtt, intval, conf->beacon_interval);
|
||||
|
||||
ath_beaconq_config(sc);
|
||||
|
||||
/* Set the computed AP beacon timers */
|
||||
|
||||
ath9k_hw_disable_interrupts(ah);
|
||||
set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
||||
ath9k_beacon_init(sc, nexttbtt, intval);
|
||||
sc->beacon.bmisscnt = 0;
|
||||
ath9k_hw_set_interrupts(ah);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -459,8 +449,8 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
|
|||
* we'll receive a BMISS interrupt when we stop seeing beacons from the AP
|
||||
* we've associated with.
|
||||
*/
|
||||
static void ath_beacon_config_sta(struct ath_softc *sc,
|
||||
struct ath_beacon_config *conf)
|
||||
static void ath9k_beacon_config_sta(struct ath_softc *sc,
|
||||
struct ath_beacon_config *conf)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
|
@ -579,97 +569,66 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
|
|||
ath9k_hw_enable_interrupts(ah);
|
||||
}
|
||||
|
||||
static void ath_beacon_config_adhoc(struct ath_softc *sc,
|
||||
struct ath_beacon_config *conf)
|
||||
static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
|
||||
struct ath_beacon_config *conf)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_common *common = ath9k_hw_common(ah);
|
||||
u32 tsf, intval, nexttbtt;
|
||||
u32 intval, nexttbtt;
|
||||
|
||||
ath9k_reset_beacon_status(sc);
|
||||
if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
|
||||
ath9k_hw_settsf64(ah, sc->beacon.bc_tstamp);
|
||||
|
||||
intval = TU_TO_USEC(conf->beacon_interval);
|
||||
tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval);
|
||||
nexttbtt = tsf + intval;
|
||||
nexttbtt = intval;
|
||||
|
||||
ath_dbg(common, BEACON, "IBSS nexttbtt %u intval %u (%u)\n",
|
||||
if (conf->enable_beacon)
|
||||
ah->imask |= ATH9K_INT_SWBA;
|
||||
else
|
||||
ah->imask &= ~ATH9K_INT_SWBA;
|
||||
|
||||
ath_dbg(common, BEACON, "IBSS nexttbtt: %u intval: %u conf_intval: %u\n",
|
||||
nexttbtt, intval, conf->beacon_interval);
|
||||
|
||||
/*
|
||||
* In IBSS mode enable the beacon timers but only enable SWBA interrupts
|
||||
* if we need to manually prepare beacon frames. Otherwise we use a
|
||||
* self-linked tx descriptor and let the hardware deal with things.
|
||||
*/
|
||||
ah->imask |= ATH9K_INT_SWBA;
|
||||
|
||||
ath_beaconq_config(sc);
|
||||
|
||||
/* Set the computed ADHOC beacon timers */
|
||||
|
||||
ath9k_hw_disable_interrupts(ah);
|
||||
ath9k_beacon_init(sc, nexttbtt, intval);
|
||||
sc->beacon.bmisscnt = 0;
|
||||
|
||||
ath9k_hw_set_interrupts(ah);
|
||||
ath9k_hw_enable_interrupts(ah);
|
||||
}
|
||||
|
||||
static bool ath9k_allow_beacon_config(struct ath_softc *sc,
|
||||
struct ieee80211_vif *vif)
|
||||
bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
||||
|
||||
/*
|
||||
* Can not have different beacon interval on multiple
|
||||
* AP interface case
|
||||
*/
|
||||
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
|
||||
(sc->nbcnvifs > 1) &&
|
||||
(vif->type == NL80211_IFTYPE_AP) &&
|
||||
(cur_conf->beacon_interval != bss_conf->beacon_int)) {
|
||||
ath_dbg(common, CONFIG,
|
||||
"Changing beacon interval of multiple AP interfaces !\n");
|
||||
return false;
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
|
||||
if ((vif->type != NL80211_IFTYPE_AP) ||
|
||||
(sc->nbcnvifs > 1)) {
|
||||
ath_dbg(common, CONFIG,
|
||||
"An AP interface is already present !\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Can not configure station vif's beacon config
|
||||
* while on AP opmode
|
||||
*/
|
||||
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
|
||||
(vif->type != NL80211_IFTYPE_AP)) {
|
||||
ath_dbg(common, CONFIG,
|
||||
"STA vif's beacon not allowed on AP mode\n");
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* Do not allow beacon config if HW was already configured
|
||||
* with another STA vif
|
||||
*/
|
||||
if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
|
||||
(vif->type == NL80211_IFTYPE_STATION) &&
|
||||
test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
|
||||
!avp->primary_sta_vif) {
|
||||
ath_dbg(common, CONFIG,
|
||||
"Beacon already configured for a station interface\n");
|
||||
return false;
|
||||
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
|
||||
if ((vif->type == NL80211_IFTYPE_STATION) &&
|
||||
test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
|
||||
!avp->primary_sta_vif) {
|
||||
ath_dbg(common, CONFIG,
|
||||
"Beacon already configured for a station interface\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||
static void ath9k_cache_beacon_config(struct ath_softc *sc,
|
||||
struct ieee80211_bss_conf *bss_conf)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
|
||||
if (!ath9k_allow_beacon_config(sc, vif))
|
||||
return;
|
||||
ath_dbg(common, BEACON,
|
||||
"Caching beacon data for BSS: %pM\n", bss_conf->bssid);
|
||||
|
||||
/* Setup the beacon configuration parameters */
|
||||
cur_conf->beacon_interval = bss_conf->beacon_int;
|
||||
cur_conf->dtim_period = bss_conf->dtim_period;
|
||||
cur_conf->listen_interval = 1;
|
||||
|
@ -694,73 +653,62 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|||
if (cur_conf->dtim_period == 0)
|
||||
cur_conf->dtim_period = 1;
|
||||
|
||||
ath_set_beacon(sc);
|
||||
}
|
||||
|
||||
static bool ath_has_valid_bslot(struct ath_softc *sc)
|
||||
void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
|
||||
u32 changed)
|
||||
{
|
||||
struct ath_vif *avp;
|
||||
int slot;
|
||||
bool found = false;
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
||||
|
||||
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 (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
|
||||
ath9k_cache_beacon_config(sc, bss_conf);
|
||||
ath9k_set_beacon(sc);
|
||||
set_bit(SC_OP_BEACONS, &sc->sc_flags);
|
||||
} else {
|
||||
/*
|
||||
* Take care of multiple interfaces when
|
||||
* enabling/disabling SWBA.
|
||||
*/
|
||||
if (changed & BSS_CHANGED_BEACON_ENABLED) {
|
||||
if (!bss_conf->enable_beacon &&
|
||||
(sc->nbcnvifs <= 1)) {
|
||||
cur_conf->enable_beacon = false;
|
||||
} else if (bss_conf->enable_beacon) {
|
||||
cur_conf->enable_beacon = true;
|
||||
ath9k_cache_beacon_config(sc, bss_conf);
|
||||
}
|
||||
}
|
||||
|
||||
if (cur_conf->beacon_interval) {
|
||||
ath9k_set_beacon(sc);
|
||||
|
||||
if (cur_conf->enable_beacon)
|
||||
set_bit(SC_OP_BEACONS, &sc->sc_flags);
|
||||
else
|
||||
clear_bit(SC_OP_BEACONS, &sc->sc_flags);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
void ath_set_beacon(struct ath_softc *sc)
|
||||
void ath9k_set_beacon(struct ath_softc *sc)
|
||||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
||||
|
||||
switch (sc->sc_ah->opmode) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
if (ath_has_valid_bslot(sc))
|
||||
ath_beacon_config_ap(sc, cur_conf);
|
||||
ath9k_beacon_config_ap(sc, cur_conf);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
ath_beacon_config_adhoc(sc, cur_conf);
|
||||
ath9k_beacon_config_adhoc(sc, cur_conf);
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
ath_beacon_config_sta(sc, cur_conf);
|
||||
ath9k_beacon_config_sta(sc, cur_conf);
|
||||
break;
|
||||
default:
|
||||
ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
set_bit(SC_OP_BEACONS, &sc->sc_flags);
|
||||
}
|
||||
|
||||
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
if (!ath_has_valid_bslot(sc)) {
|
||||
clear_bit(SC_OP_BEACONS, &sc->sc_flags);
|
||||
return;
|
||||
}
|
||||
|
||||
ath9k_ps_wakeup(sc);
|
||||
if (status) {
|
||||
/* Re-enable beaconing */
|
||||
ah->imask |= ATH9K_INT_SWBA;
|
||||
ath9k_hw_set_interrupts(ah);
|
||||
} else {
|
||||
/* Disable SWBA interrupt */
|
||||
ah->imask &= ~ATH9K_INT_SWBA;
|
||||
ath9k_hw_set_interrupts(ah);
|
||||
tasklet_kill(&sc->bcon_tasklet);
|
||||
ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
|
||||
}
|
||||
ath9k_ps_restore(sc);
|
||||
}
|
||||
|
|
|
@ -236,7 +236,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
|
|||
if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
|
||||
goto work;
|
||||
|
||||
ath_set_beacon(sc);
|
||||
ath9k_set_beacon(sc);
|
||||
|
||||
if (ah->opmode == NL80211_IFTYPE_STATION &&
|
||||
test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
|
||||
|
@ -1533,24 +1533,10 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* In case of AP mode, the HW TSF has to be reset
|
||||
* when the beacon interval changes.
|
||||
*/
|
||||
if ((changed & BSS_CHANGED_BEACON_INT) &&
|
||||
(vif->type == NL80211_IFTYPE_AP))
|
||||
set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
|
||||
|
||||
/* Configure beaconing (AP, IBSS, MESH) */
|
||||
if (ath9k_uses_beacons(vif->type) &&
|
||||
((changed & BSS_CHANGED_BEACON) ||
|
||||
(changed & BSS_CHANGED_BEACON_ENABLED) ||
|
||||
(changed & BSS_CHANGED_BEACON_INT))) {
|
||||
ath9k_set_beaconing_status(sc, false);
|
||||
if (!bss_conf->enable_beacon)
|
||||
avp->is_bslot_active = false;
|
||||
ath_beacon_config(sc, vif);
|
||||
ath9k_set_beaconing_status(sc, true);
|
||||
if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
|
||||
(changed & BSS_CHANGED_BEACON_INT)) {
|
||||
if (ath9k_allow_beacon_config(sc, vif))
|
||||
ath9k_beacon_config(sc, vif, changed);
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_ERP_SLOT) {
|
||||
|
|
|
@ -553,7 +553,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
|
|||
sc->ps_flags &= ~PS_BEACON_SYNC;
|
||||
ath_dbg(common, PS,
|
||||
"Reconfigure Beacon timers based on timestamp from the AP\n");
|
||||
ath_set_beacon(sc);
|
||||
ath9k_set_beacon(sc);
|
||||
}
|
||||
|
||||
if (ath_beacon_dtim_pending_cab(skb)) {
|
||||
|
|
Loading…
Reference in New Issue