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;
|
u16 bmiss_timeout;
|
||||||
u8 dtim_count;
|
u8 dtim_count;
|
||||||
bool enable_beacon;
|
bool enable_beacon;
|
||||||
|
bool ibss_creator;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ath_beacon {
|
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;
|
struct ath_hw *ah = sc->sc_ah;
|
||||||
|
|
||||||
ath9k_hw_disable_interrupts(ah);
|
ath9k_hw_disable_interrupts(ah);
|
||||||
ath9k_hw_reset_tsf(ah);
|
if (reset_tsf)
|
||||||
|
ath9k_hw_reset_tsf(ah);
|
||||||
ath9k_beaconq_config(sc);
|
ath9k_beaconq_config(sc);
|
||||||
ath9k_hw_beaconinit(ah, nexttbtt, intval);
|
ath9k_hw_beaconinit(ah, nexttbtt, intval);
|
||||||
sc->beacon.bmisscnt = 0;
|
sc->beacon.bmisscnt = 0;
|
||||||
@ -442,10 +447,12 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc,
|
|||||||
else
|
else
|
||||||
ah->imask &= ~ATH9K_INT_SWBA;
|
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);
|
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);
|
ath9k_reset_beacon_status(sc);
|
||||||
|
|
||||||
intval = TU_TO_USEC(conf->beacon_interval);
|
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)
|
if (conf->enable_beacon)
|
||||||
ah->imask |= ATH9K_INT_SWBA;
|
ah->imask |= ATH9K_INT_SWBA;
|
||||||
else
|
else
|
||||||
ah->imask &= ~ATH9K_INT_SWBA;
|
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);
|
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)
|
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->dtim_period = bss_conf->dtim_period;
|
||||||
cur_conf->listen_interval = 1;
|
cur_conf->listen_interval = 1;
|
||||||
cur_conf->dtim_count = 1;
|
cur_conf->dtim_count = 1;
|
||||||
|
cur_conf->ibss_creator = bss_conf->ibss_creator;
|
||||||
cur_conf->bmiss_timeout =
|
cur_conf->bmiss_timeout =
|
||||||
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
|
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 ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||||
struct ath_beacon_config *cur_conf = &sc->cur_beacon_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) {
|
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
|
||||||
ath9k_cache_beacon_config(sc, bss_conf);
|
ath9k_cache_beacon_config(sc, bss_conf);
|
||||||
ath9k_set_beacon(sc);
|
ath9k_set_beacon(sc);
|
||||||
set_bit(SC_OP_BEACONS, &sc->sc_flags);
|
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
|
* If we are joining an existing IBSS network, start beaconing
|
||||||
* enabling/disabling SWBA.
|
* only after a TSF-sync has taken place. Ensure that this
|
||||||
|
* happens by setting the appropriate flags.
|
||||||
*/
|
*/
|
||||||
if (changed & BSS_CHANGED_BEACON_ENABLED) {
|
if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator &&
|
||||||
if (!bss_conf->enable_beacon &&
|
bss_conf->enable_beacon) {
|
||||||
(sc->nbcnvifs <= 1)) {
|
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
||||||
cur_conf->enable_beacon = false;
|
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
|
||||||
} else if (bss_conf->enable_beacon) {
|
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||||
cur_conf->enable_beacon = true;
|
skip_beacon = true;
|
||||||
ath9k_cache_beacon_config(sc, bss_conf);
|
} else {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cur_conf->beacon_interval) {
|
|
||||||
ath9k_set_beacon(sc);
|
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) {
|
if (sc->ps_flags & PS_BEACON_SYNC) {
|
||||||
sc->ps_flags &= ~PS_BEACON_SYNC;
|
sc->ps_flags &= ~PS_BEACON_SYNC;
|
||||||
ath_dbg(common, PS,
|
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);
|
ath9k_set_beacon(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user