提交 5379c8a2 编写于 作者: S Sujith 提交者: John W. Linville

ath9k: Split beacon configuration into mode specific routines

This makes the code easier to understand.
Signed-off-by: NSujith <Sujith.Manoharan@atheros.com>
Signed-off-by: NJohn W. Linville <linville@tuxdriver.com>
上级 9546aae0
...@@ -458,7 +458,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id); ...@@ -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_beaconq_setup(struct ath_hw *ah);
int ath_beacon_alloc(struct ath_softc *sc, int if_id); 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_return(struct ath_softc *sc, struct ath_vif *avp);
void ath_beacon_sync(struct ath_softc *sc, int if_id);
/*******/ /*******/
/* ANI */ /* ANI */
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include "ath9k.h" #include "ath9k.h"
#define FUDGE 2
/* /*
* This function will modify certain transmit queue properties depending on * This function will modify certain transmit queue properties depending on
* the operating mode of the station (AP or AdHoc). Parameters are AIFS * the operating mode of the station (AP or AdHoc). Parameters are AIFS
...@@ -498,235 +500,231 @@ void ath_beacon_tasklet(unsigned long data) ...@@ -498,235 +500,231 @@ void ath_beacon_tasklet(unsigned long data)
} }
/* /*
* Configure the beacon and sleep timers. * 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
* When operating as an AP this resets the TSF and sets * slot. Slots that are not occupied will generate nothing.
* 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.
*/ */
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; u32 nexttbtt, intval;
if (if_id != ATH_IF_ID_ANY) { /* NB: the beacon interval is kept internally in TU's */
vif = sc->vifs[if_id]; intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
avp = (void *)vif->drv_priv; intval /= ATH_BCBUF; /* for staggered beacons */
opmode = avp->av_opmode; nexttbtt = intval;
} else { intval |= ATH9K_BEACON_RESET_TSF;
opmode = sc->sc_ah->opmode;
}
memset(&conf, 0, sizeof(struct ath_beacon_config)); /*
* 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);
conf.beacon_interval = sc->hw->conf.beacon_int ? /* Set the computed AP beacon timers */
sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
conf.listen_interval = 1;
conf.dtim_period = conf.beacon_interval;
conf.dtim_count = 1;
conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
/* extract tstamp from last beacon and convert to TU */ ath9k_hw_set_interrupts(sc->sc_ah, 0);
nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
}
/* XXX conditionalize multi-bss support? */ /*
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { * This sets up the beacon timers according to the timestamp of the last
/* * received beacon and the current TSF, configures PCF and DTIM
* For multi-bss ap support beacons are either staggered * handling, programs the sleep registers so the hardware will wakeup in
* evenly over N slots or burst together. For the former * time to receive beacons, and configures the beacon miss handling so
* arrange for the SWBA to be delivered for each slot. * we'll receive a BMISS interrupt when we stop seeing beacons from the AP
* Slots that are not occupied will generate nothing. * we've associated with.
*/ */
/* NB: the beacon interval is kept internally in TU's */ static void ath_beacon_config_sta(struct ath_softc *sc,
intval = conf.beacon_interval & ATH9K_BEACON_PERIOD; struct ath_beacon_config *conf,
intval /= ATH_BCBUF; /* for staggered beacons */ 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 { } else {
intval = conf.beacon_interval & ATH9K_BEACON_PERIOD; 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;
} }
if (nexttbtt == 0) /* e.g. for ap mode */ /*
nexttbtt = intval; * Calculate sleep duration. The configuration is given in ms.
else if (intval) /* NB: can be 0 for monitor mode */ * We ensure a multiple of the beacon period is used. Also, if the sleep
nexttbtt = roundup(nexttbtt, intval); * duration is greater than the DTIM period then it makes senses
* to make it a multiple of that.
*
* XXX fixed at 100ms
*/
DPRINTF(sc, ATH_DBG_BEACON, "nexttbtt %u intval %u (%u)\n", bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
nexttbtt, intval, conf.beacon_interval); if (bs.bs_sleepduration > bs.bs_dtimperiod)
bs.bs_sleepduration = bs.bs_dtimperiod;
/* Check for NL80211_IFTYPE_AP and sc_nostabeacons for WDS client */ /* TSF out of range threshold fixed at 1 second */
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
struct ath9k_beacon_state bs;
u64 tsf;
u32 tsftu;
int dtimperiod, dtimcount, sleepduration;
int cfpperiod, cfpcount;
/* DPRINTF(sc, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
* Setup dtim and cfp parameters according to DPRINTF(sc, ATH_DBG_BEACON,
* last beacon we received (which may be none). "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
*/ bs.bs_bmissthreshold, bs.bs_sleepduration,
dtimperiod = conf.dtim_period; bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
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 /* Set the computed STA beacon timers */
/*
* 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;
/* ath9k_hw_set_interrupts(sc->sc_ah, 0);
* Calculate the number of consecutive beacons to miss ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs);
* before taking a BMISS interrupt. The configuration sc->imask |= ATH9K_INT_BMISS;
* is specified in TU so we only need calculate based ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
* 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;
}
/* static void ath_beacon_config_adhoc(struct ath_softc *sc,
* Calculate sleep duration. The configuration is struct ath_beacon_config *conf,
* given in ms. We insure a multiple of the beacon struct ath_vif *avp)
* period is used. Also, if the sleep duration is {
* greater than the DTIM period then it makes senses u64 tsf;
* to make it a multiple of that. u32 tsftu, intval, nexttbtt;
*
* XXX fixed at 100ms
*/
bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
sleepduration);
if (bs.bs_sleepduration > bs.bs_dtimperiod)
bs.bs_sleepduration = bs.bs_dtimperiod;
/* TSF out of range threshold fixed at 1 second */ /* Pull nexttbtt forward to reflect the current TSF */
bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
DPRINTF(sc, ATH_DBG_BEACON, nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
"tsf: %llu tsftu: %u\n", tsf, tsftu); if (nexttbtt == 0)
DPRINTF(sc, ATH_DBG_BEACON, nexttbtt = intval;
"bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", else if (intval)
bs.bs_bmissthreshold, bs.bs_sleepduration, nexttbtt = roundup(nexttbtt, intval);
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); tsf = ath9k_hw_gettsf64(sc->sc_ah);
if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) { tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE;
/* Pull nexttbtt forward to reflect the current TSF */ do {
#define FUDGE 2 nexttbtt += intval;
if (!(intval & ATH9K_BEACON_RESET_TSF)) { } while (nexttbtt < tsftu);
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);
/* DPRINTF(sc, ATH_DBG_BEACON,
* In IBSS mode enable the beacon timers but only "IBSS nexttbtt %u intval %u (%u)\n",
* enable SWBA interrupts if we need to manually nexttbtt, intval, conf->beacon_interval);
* 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; * In IBSS mode enable the beacon timers but only enable SWBA interrupts
ath9k_hw_set_interrupts(ah, sc->imask); * 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);
* When using a self-linked beacon descriptor in
* ibss mode load it once here. /* Set the computed ADHOC beacon timers */
*/
if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC && ath9k_hw_set_interrupts(sc->sc_ah, 0);
(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
ath_beacon_start_adhoc(sc, 0); 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_sync(struct ath_softc *sc, int if_id) void ath_beacon_config(struct ath_softc *sc, int if_id)
{ {
/* struct ath_beacon_config conf;
* Resync beacon timers using the tsf of the struct ath_vif *avp;
* beacon frame we just received. struct ieee80211_vif *vif;
*/
ath_beacon_config(sc, if_id); /* Setup the beacon configuration parameters */
sc->sc_flags |= SC_OP_BEACONS;
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;
conf.dtim_period = conf.beacon_interval;
conf.dtim_count = 1;
conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
if (if_id != ATH_IF_ID_ANY) {
vif = sc->vifs[if_id];
avp = (struct ath_vif *)vif->drv_priv;
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;
}
sc->sc_flags |= SC_OP_BEACONS;
}
} }
...@@ -926,7 +926,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ...@@ -926,7 +926,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
/* Configure the beacon */ /* Configure the beacon */
ath_beacon_config(sc, 0); ath_beacon_config(sc, 0);
sc->sc_flags |= SC_OP_BEACONS;
/* Reset rssi stats */ /* Reset rssi stats */
sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
...@@ -2365,7 +2364,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, ...@@ -2365,7 +2364,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
if (error != 0) if (error != 0)
return error; return error;
ath_beacon_sync(sc, 0); ath_beacon_config(sc, 0);
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册