forked from Minki/linux
ath9k: Fix IBSS joiner mode
On joining an existing IBSS network, beaconing has to start only after a TSF sync has happened by receiving a beacon from the BSS. In creator mode, beaconing can start immediately after a HW reset has been done. Now that mac80211 notifies the driver of the mode type (creator/joiner) via ieee80211_bss_conf->ibss_creator, make use of it to properly setup the HW beacon timers. 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
dd5ee59bb0
commit
1a6404a1d8
@ -389,6 +389,7 @@ struct ath_beacon_config {
|
||||
u16 bmiss_timeout;
|
||||
u8 dtim_count;
|
||||
bool enable_beacon;
|
||||
bool ibss_creator;
|
||||
};
|
||||
|
||||
struct ath_beacon {
|
||||
|
@ -407,12 +407,17 @@ void ath9k_beacon_tasklet(unsigned long data)
|
||||
}
|
||||
}
|
||||
|
||||
static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval)
|
||||
/*
|
||||
* Both nexttbtt and intval have to be in usecs.
|
||||
*/
|
||||
static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
|
||||
u32 intval, bool reset_tsf)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
||||
ath9k_hw_disable_interrupts(ah);
|
||||
ath9k_hw_reset_tsf(ah);
|
||||
if (reset_tsf)
|
||||
ath9k_hw_reset_tsf(ah);
|
||||
ath9k_beaconq_config(sc);
|
||||
ath9k_hw_beaconinit(ah, nexttbtt, intval);
|
||||
sc->beacon.bmisscnt = 0;
|
||||
@ -442,10 +447,12 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
|
||||
else
|
||||
ah->imask &= ~ATH9K_INT_SWBA;
|
||||
|
||||
ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n",
|
||||
ath_dbg(common, BEACON,
|
||||
"AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
|
||||
(conf->enable_beacon) ? "Enable" : "Disable",
|
||||
nexttbtt, intval, conf->beacon_interval);
|
||||
|
||||
ath9k_beacon_init(sc, nexttbtt, intval);
|
||||
ath9k_beacon_init(sc, nexttbtt, intval, true);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -586,17 +593,45 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
|
||||
ath9k_reset_beacon_status(sc);
|
||||
|
||||
intval = TU_TO_USEC(conf->beacon_interval);
|
||||
nexttbtt = intval;
|
||||
|
||||
if (conf->ibss_creator) {
|
||||
nexttbtt = intval;
|
||||
} else {
|
||||
u32 tbtt, offset, tsftu;
|
||||
u64 tsf;
|
||||
|
||||
/*
|
||||
* Pull nexttbtt forward to reflect the current
|
||||
* sync'd TSF.
|
||||
*/
|
||||
tsf = ath9k_hw_gettsf64(ah);
|
||||
tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE;
|
||||
offset = tsftu % conf->beacon_interval;
|
||||
tbtt = tsftu - offset;
|
||||
if (offset)
|
||||
tbtt += conf->beacon_interval;
|
||||
|
||||
nexttbtt = TU_TO_USEC(tbtt);
|
||||
}
|
||||
|
||||
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",
|
||||
ath_dbg(common, BEACON,
|
||||
"IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n",
|
||||
(conf->enable_beacon) ? "Enable" : "Disable",
|
||||
nexttbtt, intval, conf->beacon_interval);
|
||||
|
||||
ath9k_beacon_init(sc, nexttbtt, intval);
|
||||
ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator);
|
||||
|
||||
/*
|
||||
* Set the global 'beacon has been configured' flag for the
|
||||
* joiner case in IBSS mode.
|
||||
*/
|
||||
if (!conf->ibss_creator && conf->enable_beacon)
|
||||
set_bit(SC_OP_BEACONS, &sc->sc_flags);
|
||||
}
|
||||
|
||||
bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||
@ -639,6 +674,7 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc,
|
||||
cur_conf->dtim_period = bss_conf->dtim_period;
|
||||
cur_conf->listen_interval = 1;
|
||||
cur_conf->dtim_count = 1;
|
||||
cur_conf->ibss_creator = bss_conf->ibss_creator;
|
||||
cur_conf->bmiss_timeout =
|
||||
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
|
||||
|
||||
@ -666,34 +702,59 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
|
||||
{
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
|
||||
unsigned long flags;
|
||||
bool skip_beacon = false;
|
||||
|
||||
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 {
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure the HW beacon registers only when we have a valid
|
||||
* beacon interval.
|
||||
*/
|
||||
if (cur_conf->beacon_interval) {
|
||||
/*
|
||||
* Take care of multiple interfaces when
|
||||
* enabling/disabling SWBA.
|
||||
* If we are joining an existing IBSS network, start beaconing
|
||||
* only after a TSF-sync has taken place. Ensure that this
|
||||
* happens by setting the appropriate flags.
|
||||
*/
|
||||
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) {
|
||||
if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator &&
|
||||
bss_conf->enable_beacon) {
|
||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
||||
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
|
||||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||
skip_beacon = true;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not set the SC_OP_BEACONS flag for IBSS joiner mode
|
||||
* here, it is done in ath9k_beacon_config_adhoc().
|
||||
*/
|
||||
if (cur_conf->enable_beacon && !skip_beacon)
|
||||
set_bit(SC_OP_BEACONS, &sc->sc_flags);
|
||||
else
|
||||
clear_bit(SC_OP_BEACONS, &sc->sc_flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -533,7 +533,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
|
||||
if (sc->ps_flags & PS_BEACON_SYNC) {
|
||||
sc->ps_flags &= ~PS_BEACON_SYNC;
|
||||
ath_dbg(common, PS,
|
||||
"Reconfigure Beacon timers based on timestamp from the AP\n");
|
||||
"Reconfigure beacon timers based on synchronized timestamp\n");
|
||||
ath9k_set_beacon(sc);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user