提交 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,103 +500,81 @@ void ath_beacon_tasklet(unsigned long data) ...@@ -498,103 +500,81 @@ 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));
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;
/* extract tstamp from last beacon and convert to TU */
nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
/* XXX conditionalize multi-bss support? */
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
/* /*
* For multi-bss ap support beacons are either staggered * In AP mode we enable the beacon timers and SWBA interrupts to
* evenly over N slots or burst together. For the former * prepare beacon frames.
* 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 |= ATH9K_BEACON_ENA;
intval = conf.beacon_interval & ATH9K_BEACON_PERIOD; sc->imask |= ATH9K_INT_SWBA;
intval /= ATH_BCBUF; /* for staggered beacons */ ath_beaconq_config(sc);
} else {
intval = conf.beacon_interval & ATH9K_BEACON_PERIOD;
}
if (nexttbtt == 0) /* e.g. for ap mode */ /* Set the computed AP beacon timers */
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", ath9k_hw_set_interrupts(sc->sc_ah, 0);
nexttbtt, intval, conf.beacon_interval); ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
}
/* Check for NL80211_IFTYPE_AP and sc_nostabeacons for WDS client */ /*
if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { * 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; struct ath9k_beacon_state bs;
u64 tsf;
u32 tsftu;
int dtimperiod, dtimcount, sleepduration; int dtimperiod, dtimcount, sleepduration;
int cfpperiod, cfpcount; 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 * Setup dtim and cfp parameters according to
* last beacon we received (which may be none). * last beacon we received (which may be none).
*/ */
dtimperiod = conf.dtim_period; dtimperiod = conf->dtim_period;
if (dtimperiod <= 0) /* NB: 0 if not known */ if (dtimperiod <= 0) /* NB: 0 if not known */
dtimperiod = 1; dtimperiod = 1;
dtimcount = conf.dtim_count; dtimcount = conf->dtim_count;
if (dtimcount >= dtimperiod) /* NB: sanity check */ if (dtimcount >= dtimperiod) /* NB: sanity check */
dtimcount = 0; dtimcount = 0;
cfpperiod = 1; /* NB: no PCF support yet */ cfpperiod = 1; /* NB: no PCF support yet */
cfpcount = 0; cfpcount = 0;
sleepduration = conf.listen_interval * intval; sleepduration = conf->listen_interval * intval;
if (sleepduration <= 0) if (sleepduration <= 0)
sleepduration = intval; sleepduration = intval;
#define FUDGE 2
/* /*
* Pull nexttbtt forward to reflect the current * Pull nexttbtt forward to reflect the current
* TSF and calculate dtim+cfp state for the result. * TSF and calculate dtim+cfp state for the result.
*/ */
tsf = ath9k_hw_gettsf64(ah); tsf = ath9k_hw_gettsf64(sc->sc_ah);
tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
do { do {
nexttbtt += intval; nexttbtt += intval;
...@@ -604,8 +584,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) ...@@ -604,8 +584,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
cfpcount = cfpperiod - 1; cfpcount = cfpperiod - 1;
} }
} while (nexttbtt < tsftu); } while (nexttbtt < tsftu);
#undef FUDGE
memset(&bs, 0, sizeof(bs));
bs.bs_intval = intval; bs.bs_intval = intval;
bs.bs_nexttbtt = nexttbtt; bs.bs_nexttbtt = nexttbtt;
bs.bs_dtimperiod = dtimperiod*intval; bs.bs_dtimperiod = dtimperiod*intval;
...@@ -615,18 +594,16 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) ...@@ -615,18 +594,16 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
bs.bs_cfpmaxduration = 0; bs.bs_cfpmaxduration = 0;
/* /*
* Calculate the number of consecutive beacons to miss * Calculate the number of consecutive beacons to miss* before taking
* before taking a BMISS interrupt. The configuration * a BMISS interrupt. The configuration is specified in TU so we only
* is specified in TU so we only need calculate based * need calculate based on the beacon interval. Note that we clamp the
* on the beacon interval. Note that we clamp the
* result to at most 15 beacons. * result to at most 15 beacons.
*/ */
if (sleepduration > intval) { if (sleepduration > intval) {
bs.bs_bmissthreshold = conf.listen_interval * bs.bs_bmissthreshold = conf->listen_interval *
ATH_DEFAULT_BMISS_LIMIT / 2; ATH_DEFAULT_BMISS_LIMIT / 2;
} else { } else {
bs.bs_bmissthreshold = bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
DIV_ROUND_UP(conf.bmiss_timeout, intval);
if (bs.bs_bmissthreshold > 15) if (bs.bs_bmissthreshold > 15)
bs.bs_bmissthreshold = 15; bs.bs_bmissthreshold = 15;
else if (bs.bs_bmissthreshold <= 0) else if (bs.bs_bmissthreshold <= 0)
...@@ -634,99 +611,120 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) ...@@ -634,99 +611,120 @@ void ath_beacon_config(struct ath_softc *sc, int if_id)
} }
/* /*
* Calculate sleep duration. The configuration is * Calculate sleep duration. The configuration is given in ms.
* given in ms. We insure a multiple of the beacon * We ensure a multiple of the beacon period is used. Also, if the sleep
* period is used. Also, if the sleep duration is * duration is greater than the DTIM period then it makes senses
* greater than the DTIM period then it makes senses
* to make it a multiple of that. * to make it a multiple of that.
* *
* XXX fixed at 100ms * XXX fixed at 100ms
*/ */
bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
sleepduration);
if (bs.bs_sleepduration > bs.bs_dtimperiod) if (bs.bs_sleepduration > bs.bs_dtimperiod)
bs.bs_sleepduration = bs.bs_dtimperiod; bs.bs_sleepduration = bs.bs_dtimperiod;
/* TSF out of range threshold fixed at 1 second */ /* TSF out of range threshold fixed at 1 second */
bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
DPRINTF(sc, ATH_DBG_BEACON, DPRINTF(sc, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
"tsf: %llu tsftu: %u\n", tsf, tsftu);
DPRINTF(sc, ATH_DBG_BEACON, DPRINTF(sc, ATH_DBG_BEACON,
"bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
bs.bs_bmissthreshold, bs.bs_sleepduration, bs.bs_bmissthreshold, bs.bs_sleepduration,
bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
ath9k_hw_set_interrupts(ah, 0); /* Set the computed STA beacon timers */
ath9k_hw_set_sta_beacon_timers(ah, &bs);
ath9k_hw_set_interrupts(sc->sc_ah, 0);
ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs);
sc->imask |= ATH9K_INT_BMISS; sc->imask |= ATH9K_INT_BMISS;
ath9k_hw_set_interrupts(ah, sc->imask); ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
} else { }
static void ath_beacon_config_adhoc(struct ath_softc *sc,
struct ath_beacon_config *conf,
struct ath_vif *avp)
{
u64 tsf; u64 tsf;
u32 tsftu; u32 tsftu, intval, nexttbtt;
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
ath9k_hw_set_interrupts(ah, 0);
if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) {
/* Pull nexttbtt forward to reflect the current TSF */ /* Pull nexttbtt forward to reflect the current TSF */
#define FUDGE 2
if (!(intval & ATH9K_BEACON_RESET_TSF)) { nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
tsf = ath9k_hw_gettsf64(ah); if (nexttbtt == 0)
tsftu = TSF_TO_TU((u32)(tsf>>32), nexttbtt = intval;
(u32)tsf) + FUDGE; 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 { do {
nexttbtt += intval; nexttbtt += intval;
} while (nexttbtt < tsftu); } while (nexttbtt < tsftu);
}
#undef FUDGE
DPRINTF(sc, ATH_DBG_BEACON, DPRINTF(sc, ATH_DBG_BEACON,
"IBSS nexttbtt %u intval %u (%u)\n", "IBSS nexttbtt %u intval %u (%u)\n",
nexttbtt, intval & ~ATH9K_BEACON_RESET_TSF, nexttbtt, intval, conf->beacon_interval);
conf.beacon_interval);
/* /*
* In IBSS mode enable the beacon timers but only * In IBSS mode enable the beacon timers but only enable SWBA interrupts
* enable SWBA interrupts if we need to manually * if we need to manually prepare beacon frames. Otherwise we use a
* prepare beacon frames. Otherwise we use a * self-linked tx descriptor and let the hardware deal with things.
* 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; intval |= ATH9K_BEACON_ENA;
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
sc->imask |= ATH9K_INT_SWBA; sc->imask |= ATH9K_INT_SWBA;
ath_beaconq_config(sc); ath_beaconq_config(sc);
}
ath9k_hw_beaconinit(ah, nexttbtt, intval); /* 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; sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(ah, sc->imask); ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
/* if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
* 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); 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 */
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; 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.
先完成此消息的编辑!
想要评论请 注册