ath9k: Split beacon configuration into mode specific routines
This makes the code easier to understand. Signed-off-by: Sujith <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Родитель
9546aae086
Коммит
5379c8a266
|
@ -458,7 +458,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id);
|
|||
int ath_beaconq_setup(struct ath_hw *ah);
|
||||
int ath_beacon_alloc(struct ath_softc *sc, int if_id);
|
||||
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
|
||||
void ath_beacon_sync(struct ath_softc *sc, int if_id);
|
||||
|
||||
/*******/
|
||||
/* ANI */
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include "ath9k.h"
|
||||
|
||||
#define FUDGE 2
|
||||
|
||||
/*
|
||||
* This function will modify certain transmit queue properties depending on
|
||||
* the operating mode of the station (AP or AdHoc). Parameters are AIFS
|
||||
|
@ -498,39 +500,204 @@ void ath_beacon_tasklet(unsigned long data)
|
|||
}
|
||||
|
||||
/*
|
||||
* Configure the beacon and sleep timers.
|
||||
*
|
||||
* When operating as an AP this resets the TSF and sets
|
||||
* up the hardware to notify us when we need to issue beacons.
|
||||
*
|
||||
* When operating in station mode this sets up the beacon
|
||||
* timers according to the timestamp of the last received
|
||||
* beacon and the current TSF, configures PCF and DTIM
|
||||
* handling, programs the sleep registers so the hardware
|
||||
* will wakeup in time to receive beacons, and configures
|
||||
* the beacon miss handling so we'll receive a BMISS
|
||||
* interrupt when we stop seeing beacons from the AP
|
||||
* we've associated with.
|
||||
* For multi-bss ap support beacons are either staggered evenly over N slots or
|
||||
* burst together. For the former arrange for the SWBA to be delivered for each
|
||||
* slot. Slots that are not occupied will generate nothing.
|
||||
*/
|
||||
void ath_beacon_config(struct ath_softc *sc, int if_id)
|
||||
static void ath_beacon_config_ap(struct ath_softc *sc,
|
||||
struct ath_beacon_config *conf,
|
||||
struct ath_vif *avp)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
struct ath_beacon_config conf;
|
||||
struct ath_vif *avp;
|
||||
enum nl80211_iftype opmode;
|
||||
u32 nexttbtt, intval;
|
||||
|
||||
if (if_id != ATH_IF_ID_ANY) {
|
||||
vif = sc->vifs[if_id];
|
||||
avp = (void *)vif->drv_priv;
|
||||
opmode = avp->av_opmode;
|
||||
/* NB: the beacon interval is kept internally in TU's */
|
||||
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
|
||||
intval /= ATH_BCBUF; /* for staggered beacons */
|
||||
nexttbtt = intval;
|
||||
intval |= ATH9K_BEACON_RESET_TSF;
|
||||
|
||||
/*
|
||||
* In AP mode we enable the beacon timers and SWBA interrupts to
|
||||
* prepare beacon frames.
|
||||
*/
|
||||
intval |= ATH9K_BEACON_ENA;
|
||||
sc->imask |= ATH9K_INT_SWBA;
|
||||
ath_beaconq_config(sc);
|
||||
|
||||
/* Set the computed AP beacon timers */
|
||||
|
||||
ath9k_hw_set_interrupts(sc->sc_ah, 0);
|
||||
ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
|
||||
sc->beacon.bmisscnt = 0;
|
||||
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
|
||||
}
|
||||
|
||||
/*
|
||||
* This sets up the beacon timers according to the timestamp of the last
|
||||
* received beacon and the current TSF, configures PCF and DTIM
|
||||
* handling, programs the sleep registers so the hardware will wakeup in
|
||||
* time to receive beacons, and configures the beacon miss handling so
|
||||
* 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,
|
||||
struct ath_vif *avp)
|
||||
{
|
||||
struct ath9k_beacon_state bs;
|
||||
int dtimperiod, dtimcount, sleepduration;
|
||||
int cfpperiod, cfpcount;
|
||||
u32 nexttbtt = 0, intval, tsftu;
|
||||
u64 tsf;
|
||||
|
||||
memset(&bs, 0, sizeof(bs));
|
||||
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
|
||||
|
||||
/*
|
||||
* Setup dtim and cfp parameters according to
|
||||
* last beacon we received (which may be none).
|
||||
*/
|
||||
dtimperiod = conf->dtim_period;
|
||||
if (dtimperiod <= 0) /* NB: 0 if not known */
|
||||
dtimperiod = 1;
|
||||
dtimcount = conf->dtim_count;
|
||||
if (dtimcount >= dtimperiod) /* NB: sanity check */
|
||||
dtimcount = 0;
|
||||
cfpperiod = 1; /* NB: no PCF support yet */
|
||||
cfpcount = 0;
|
||||
|
||||
sleepduration = conf->listen_interval * intval;
|
||||
if (sleepduration <= 0)
|
||||
sleepduration = intval;
|
||||
|
||||
/*
|
||||
* Pull nexttbtt forward to reflect the current
|
||||
* TSF and calculate dtim+cfp state for the result.
|
||||
*/
|
||||
tsf = ath9k_hw_gettsf64(sc->sc_ah);
|
||||
tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
|
||||
do {
|
||||
nexttbtt += intval;
|
||||
if (--dtimcount < 0) {
|
||||
dtimcount = dtimperiod - 1;
|
||||
if (--cfpcount < 0)
|
||||
cfpcount = cfpperiod - 1;
|
||||
}
|
||||
} while (nexttbtt < tsftu);
|
||||
|
||||
bs.bs_intval = intval;
|
||||
bs.bs_nexttbtt = nexttbtt;
|
||||
bs.bs_dtimperiod = dtimperiod*intval;
|
||||
bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
|
||||
bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
|
||||
bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
|
||||
bs.bs_cfpmaxduration = 0;
|
||||
|
||||
/*
|
||||
* Calculate the number of consecutive beacons to miss* before taking
|
||||
* a BMISS interrupt. The configuration is specified in TU so we only
|
||||
* need calculate based on the beacon interval. Note that we clamp the
|
||||
* result to at most 15 beacons.
|
||||
*/
|
||||
if (sleepduration > intval) {
|
||||
bs.bs_bmissthreshold = conf->listen_interval *
|
||||
ATH_DEFAULT_BMISS_LIMIT / 2;
|
||||
} else {
|
||||
opmode = sc->sc_ah->opmode;
|
||||
bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
|
||||
if (bs.bs_bmissthreshold > 15)
|
||||
bs.bs_bmissthreshold = 15;
|
||||
else if (bs.bs_bmissthreshold <= 0)
|
||||
bs.bs_bmissthreshold = 1;
|
||||
}
|
||||
|
||||
memset(&conf, 0, sizeof(struct ath_beacon_config));
|
||||
/*
|
||||
* Calculate sleep duration. The configuration is given in ms.
|
||||
* We ensure a multiple of the beacon period is used. Also, if the sleep
|
||||
* duration is greater than the DTIM period then it makes senses
|
||||
* to make it a multiple of that.
|
||||
*
|
||||
* XXX fixed at 100ms
|
||||
*/
|
||||
|
||||
bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
|
||||
if (bs.bs_sleepduration > bs.bs_dtimperiod)
|
||||
bs.bs_sleepduration = bs.bs_dtimperiod;
|
||||
|
||||
/* TSF out of range threshold fixed at 1 second */
|
||||
bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
|
||||
|
||||
DPRINTF(sc, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
|
||||
DPRINTF(sc, ATH_DBG_BEACON,
|
||||
"bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
|
||||
bs.bs_bmissthreshold, bs.bs_sleepduration,
|
||||
bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
|
||||
|
||||
/* Set the computed STA beacon timers */
|
||||
|
||||
ath9k_hw_set_interrupts(sc->sc_ah, 0);
|
||||
ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs);
|
||||
sc->imask |= ATH9K_INT_BMISS;
|
||||
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
|
||||
}
|
||||
|
||||
static void ath_beacon_config_adhoc(struct ath_softc *sc,
|
||||
struct ath_beacon_config *conf,
|
||||
struct ath_vif *avp)
|
||||
{
|
||||
u64 tsf;
|
||||
u32 tsftu, intval, nexttbtt;
|
||||
|
||||
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
|
||||
|
||||
/* Pull nexttbtt forward to reflect the current TSF */
|
||||
|
||||
nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
|
||||
if (nexttbtt == 0)
|
||||
nexttbtt = intval;
|
||||
else if (intval)
|
||||
nexttbtt = roundup(nexttbtt, intval);
|
||||
|
||||
tsf = ath9k_hw_gettsf64(sc->sc_ah);
|
||||
tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE;
|
||||
do {
|
||||
nexttbtt += intval;
|
||||
} while (nexttbtt < tsftu);
|
||||
|
||||
DPRINTF(sc, ATH_DBG_BEACON,
|
||||
"IBSS nexttbtt %u intval %u (%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.
|
||||
*/
|
||||
intval |= ATH9K_BEACON_ENA;
|
||||
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
|
||||
sc->imask |= ATH9K_INT_SWBA;
|
||||
|
||||
ath_beaconq_config(sc);
|
||||
|
||||
/* Set the computed ADHOC beacon timers */
|
||||
|
||||
ath9k_hw_set_interrupts(sc->sc_ah, 0);
|
||||
ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
|
||||
sc->beacon.bmisscnt = 0;
|
||||
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
|
||||
ath_beacon_start_adhoc(sc, 0);
|
||||
}
|
||||
|
||||
void ath_beacon_config(struct ath_softc *sc, int if_id)
|
||||
{
|
||||
struct ath_beacon_config conf;
|
||||
struct ath_vif *avp;
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
/* Setup the beacon configuration parameters */
|
||||
|
||||
memset(&conf, 0, sizeof(struct ath_beacon_config));
|
||||
conf.beacon_interval = sc->hw->conf.beacon_int ?
|
||||
sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
|
||||
conf.listen_interval = 1;
|
||||
|
@ -538,195 +705,26 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
|
|||
conf.dtim_count = 1;
|
||||
conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
|
||||
|
||||
/* extract tstamp from last beacon and convert to TU */
|
||||
nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
|
||||
if (if_id != ATH_IF_ID_ANY) {
|
||||
vif = sc->vifs[if_id];
|
||||
avp = (struct ath_vif *)vif->drv_priv;
|
||||
|
||||
/* XXX conditionalize multi-bss support? */
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
|
||||
/*
|
||||
* For multi-bss ap support beacons are either staggered
|
||||
* evenly over N slots or burst together. For the former
|
||||
* arrange for the SWBA to be delivered for each slot.
|
||||
* Slots that are not occupied will generate nothing.
|
||||
*/
|
||||
/* NB: the beacon interval is kept internally in TU's */
|
||||
intval = conf.beacon_interval & ATH9K_BEACON_PERIOD;
|
||||
intval /= ATH_BCBUF; /* for staggered beacons */
|
||||
} else {
|
||||
intval = conf.beacon_interval & ATH9K_BEACON_PERIOD;
|
||||
}
|
||||
|
||||
if (nexttbtt == 0) /* e.g. for ap mode */
|
||||
nexttbtt = intval;
|
||||
else if (intval) /* NB: can be 0 for monitor mode */
|
||||
nexttbtt = roundup(nexttbtt, intval);
|
||||
|
||||
DPRINTF(sc, ATH_DBG_BEACON, "nexttbtt %u intval %u (%u)\n",
|
||||
nexttbtt, intval, conf.beacon_interval);
|
||||
|
||||
/* Check for NL80211_IFTYPE_AP and sc_nostabeacons for WDS client */
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
|
||||
struct ath9k_beacon_state bs;
|
||||
u64 tsf;
|
||||
u32 tsftu;
|
||||
int dtimperiod, dtimcount, sleepduration;
|
||||
int cfpperiod, cfpcount;
|
||||
|
||||
/*
|
||||
* Setup dtim and cfp parameters according to
|
||||
* last beacon we received (which may be none).
|
||||
*/
|
||||
dtimperiod = conf.dtim_period;
|
||||
if (dtimperiod <= 0) /* NB: 0 if not known */
|
||||
dtimperiod = 1;
|
||||
dtimcount = conf.dtim_count;
|
||||
if (dtimcount >= dtimperiod) /* NB: sanity check */
|
||||
dtimcount = 0;
|
||||
cfpperiod = 1; /* NB: no PCF support yet */
|
||||
cfpcount = 0;
|
||||
|
||||
sleepduration = conf.listen_interval * intval;
|
||||
if (sleepduration <= 0)
|
||||
sleepduration = intval;
|
||||
|
||||
#define FUDGE 2
|
||||
/*
|
||||
* Pull nexttbtt forward to reflect the current
|
||||
* TSF and calculate dtim+cfp state for the result.
|
||||
*/
|
||||
tsf = ath9k_hw_gettsf64(ah);
|
||||
tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
|
||||
do {
|
||||
nexttbtt += intval;
|
||||
if (--dtimcount < 0) {
|
||||
dtimcount = dtimperiod - 1;
|
||||
if (--cfpcount < 0)
|
||||
cfpcount = cfpperiod - 1;
|
||||
}
|
||||
} while (nexttbtt < tsftu);
|
||||
#undef FUDGE
|
||||
memset(&bs, 0, sizeof(bs));
|
||||
bs.bs_intval = intval;
|
||||
bs.bs_nexttbtt = nexttbtt;
|
||||
bs.bs_dtimperiod = dtimperiod*intval;
|
||||
bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
|
||||
bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
|
||||
bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
|
||||
bs.bs_cfpmaxduration = 0;
|
||||
|
||||
/*
|
||||
* Calculate the number of consecutive beacons to miss
|
||||
* before taking a BMISS interrupt. The configuration
|
||||
* is specified in TU so we only need calculate based
|
||||
* on the beacon interval. Note that we clamp the
|
||||
* result to at most 15 beacons.
|
||||
*/
|
||||
if (sleepduration > intval) {
|
||||
bs.bs_bmissthreshold = conf.listen_interval *
|
||||
ATH_DEFAULT_BMISS_LIMIT / 2;
|
||||
} else {
|
||||
bs.bs_bmissthreshold =
|
||||
DIV_ROUND_UP(conf.bmiss_timeout, intval);
|
||||
if (bs.bs_bmissthreshold > 15)
|
||||
bs.bs_bmissthreshold = 15;
|
||||
else if (bs.bs_bmissthreshold <= 0)
|
||||
bs.bs_bmissthreshold = 1;
|
||||
switch(avp->av_opmode) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
ath_beacon_config_ap(sc, &conf, avp);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
ath_beacon_config_adhoc(sc, &conf, avp);
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
ath_beacon_config_sta(sc, &conf, avp);
|
||||
break;
|
||||
default:
|
||||
DPRINTF(sc, ATH_DBG_CONFIG,
|
||||
"Unsupported beaconing mode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate sleep duration. The configuration is
|
||||
* given in ms. We insure a multiple of the beacon
|
||||
* period is used. Also, if the sleep duration is
|
||||
* greater than the DTIM period then it makes senses
|
||||
* to make it a multiple of that.
|
||||
*
|
||||
* XXX fixed at 100ms
|
||||
*/
|
||||
|
||||
bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100),
|
||||
sleepduration);
|
||||
if (bs.bs_sleepduration > bs.bs_dtimperiod)
|
||||
bs.bs_sleepduration = bs.bs_dtimperiod;
|
||||
|
||||
/* TSF out of range threshold fixed at 1 second */
|
||||
bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
|
||||
|
||||
DPRINTF(sc, ATH_DBG_BEACON,
|
||||
"tsf: %llu tsftu: %u\n", tsf, tsftu);
|
||||
DPRINTF(sc, ATH_DBG_BEACON,
|
||||
"bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
|
||||
bs.bs_bmissthreshold, bs.bs_sleepduration,
|
||||
bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
|
||||
|
||||
ath9k_hw_set_interrupts(ah, 0);
|
||||
ath9k_hw_set_sta_beacon_timers(ah, &bs);
|
||||
sc->imask |= ATH9K_INT_BMISS;
|
||||
ath9k_hw_set_interrupts(ah, sc->imask);
|
||||
} else {
|
||||
u64 tsf;
|
||||
u32 tsftu;
|
||||
|
||||
ath9k_hw_set_interrupts(ah, 0);
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) {
|
||||
/* Pull nexttbtt forward to reflect the current TSF */
|
||||
#define FUDGE 2
|
||||
if (!(intval & ATH9K_BEACON_RESET_TSF)) {
|
||||
tsf = ath9k_hw_gettsf64(ah);
|
||||
tsftu = TSF_TO_TU((u32)(tsf>>32),
|
||||
(u32)tsf) + FUDGE;
|
||||
do {
|
||||
nexttbtt += intval;
|
||||
} while (nexttbtt < tsftu);
|
||||
}
|
||||
#undef FUDGE
|
||||
DPRINTF(sc, ATH_DBG_BEACON,
|
||||
"IBSS nexttbtt %u intval %u (%u)\n",
|
||||
nexttbtt, intval & ~ATH9K_BEACON_RESET_TSF,
|
||||
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.
|
||||
*/
|
||||
intval |= ATH9K_BEACON_ENA;
|
||||
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
|
||||
sc->imask |= ATH9K_INT_SWBA;
|
||||
ath_beaconq_config(sc);
|
||||
} else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
|
||||
if (nexttbtt == intval)
|
||||
intval |= ATH9K_BEACON_RESET_TSF;
|
||||
/*
|
||||
* In AP mode we enable the beacon timers and
|
||||
* SWBA interrupts to prepare beacon frames.
|
||||
*/
|
||||
intval |= ATH9K_BEACON_ENA;
|
||||
sc->imask |= ATH9K_INT_SWBA;
|
||||
ath_beaconq_config(sc);
|
||||
}
|
||||
|
||||
ath9k_hw_beaconinit(ah, nexttbtt, intval);
|
||||
sc->beacon.bmisscnt = 0;
|
||||
ath9k_hw_set_interrupts(ah, sc->imask);
|
||||
|
||||
/*
|
||||
* When using a self-linked beacon descriptor in
|
||||
* ibss mode load it once here.
|
||||
*/
|
||||
if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
|
||||
(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
|
||||
ath_beacon_start_adhoc(sc, 0);
|
||||
sc->sc_flags |= SC_OP_BEACONS;
|
||||
}
|
||||
}
|
||||
|
||||
void ath_beacon_sync(struct ath_softc *sc, int if_id)
|
||||
{
|
||||
/*
|
||||
* Resync beacon timers using the tsf of the
|
||||
* beacon frame we just received.
|
||||
*/
|
||||
ath_beacon_config(sc, if_id);
|
||||
sc->sc_flags |= SC_OP_BEACONS;
|
||||
}
|
||||
|
|
|
@ -926,7 +926,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
|
|||
|
||||
/* Configure the beacon */
|
||||
ath_beacon_config(sc, 0);
|
||||
sc->sc_flags |= SC_OP_BEACONS;
|
||||
|
||||
/* Reset rssi stats */
|
||||
sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
|
||||
|
@ -2365,7 +2364,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
|
|||
if (error != 0)
|
||||
return error;
|
||||
|
||||
ath_beacon_sync(sc, 0);
|
||||
ath_beacon_config(sc, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче