ath9k: improve precision of beacon timer calculations
SVN-Revision: 26248
This commit is contained in:
parent
c12de7c4c1
commit
4838baefa7
1 changed files with 317 additions and 0 deletions
317
package/mac80211/patches/561-ath9k_fix_staggered_beacons.patch
Normal file
317
package/mac80211/patches/561-ath9k_fix_staggered_beacons.patch
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/beacon.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
|
||||||
|
@@ -57,8 +57,8 @@ int ath_beaconq_config(struct ath_softc
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Associates the beacon frame buffer with a transmit descriptor. Will set
|
||||||
|
- * up all required antenna switch parameters, rate codes, and channel flags.
|
||||||
|
- * Beacons are always sent out at the lowest rate, and are not retried.
|
||||||
|
+ * up rate codes, and channel flags. Beacons are always sent out at the
|
||||||
|
+ * lowest rate, and are not retried.
|
||||||
|
*/
|
||||||
|
static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
|
||||||
|
struct ath_buf *bf, int rateidx)
|
||||||
|
@@ -68,7 +68,7 @@ static void ath_beacon_setup(struct ath_
|
||||||
|
struct ath_common *common = ath9k_hw_common(ah);
|
||||||
|
struct ath_desc *ds;
|
||||||
|
struct ath9k_11n_rate_series series[4];
|
||||||
|
- int flags, antenna, ctsrate = 0, ctsduration = 0;
|
||||||
|
+ int flags, ctsrate = 0, ctsduration = 0;
|
||||||
|
struct ieee80211_supported_band *sband;
|
||||||
|
u8 rate = 0;
|
||||||
|
|
||||||
|
@@ -76,12 +76,6 @@ static void ath_beacon_setup(struct ath_
|
||||||
|
flags = ATH9K_TXDESC_NOACK;
|
||||||
|
|
||||||
|
ds->ds_link = 0;
|
||||||
|
- /*
|
||||||
|
- * Switch antenna every beacon.
|
||||||
|
- * Should only switch every beacon period, not for every SWBA
|
||||||
|
- * XXX assumes two antennae
|
||||||
|
- */
|
||||||
|
- antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1);
|
||||||
|
|
||||||
|
sband = &sc->sbands[common->hw->conf.channel->band];
|
||||||
|
rate = sband->bitrates[rateidx].hw_value;
|
||||||
|
@@ -278,7 +272,7 @@ int ath_beacon_alloc(struct ath_softc *s
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
|
||||||
|
- sc->beacon.bc_tstamp = le64_to_cpu(tstamp);
|
||||||
|
+ sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp);
|
||||||
|
/* Calculate a TSF adjustment factor required for staggered beacons. */
|
||||||
|
if (avp->av_bslot > 0) {
|
||||||
|
u64 tsfadjust;
|
||||||
|
@@ -294,8 +288,8 @@ int ath_beacon_alloc(struct ath_softc *s
|
||||||
|
* adjustment. Other slots are adjusted to get the timestamp
|
||||||
|
* close to the TBTT for the BSS.
|
||||||
|
*/
|
||||||
|
- tsfadjust = intval * avp->av_bslot / ATH_BCBUF;
|
||||||
|
- avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
|
||||||
|
+ tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF;
|
||||||
|
+ avp->tsf_adjust = cpu_to_le64(tsfadjust);
|
||||||
|
|
||||||
|
ath_dbg(common, ATH_DBG_BEACON,
|
||||||
|
"stagger beacons, bslot %d intval %u tsfadjust %llu\n",
|
||||||
|
@@ -401,8 +395,9 @@ void ath_beacon_tasklet(unsigned long da
|
||||||
|
intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
|
||||||
|
|
||||||
|
tsf = ath9k_hw_gettsf64(ah);
|
||||||
|
- tsftu = TSF_TO_TU(tsf>>32, tsf);
|
||||||
|
- slot = ((tsftu % intval) * ATH_BCBUF) / intval;
|
||||||
|
+ tsf += TU_TO_USEC(ah->config.sw_beacon_response_time);
|
||||||
|
+ tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
|
||||||
|
+ slot = (tsftu % (intval * ATH_BCBUF)) / intval;
|
||||||
|
/*
|
||||||
|
* Reverse the slot order to get slot 0 on the TBTT offset that does
|
||||||
|
* not require TSF adjustment and other slots adding
|
||||||
|
@@ -415,7 +410,7 @@ void ath_beacon_tasklet(unsigned long da
|
||||||
|
|
||||||
|
ath_dbg(common, ATH_DBG_BEACON,
|
||||||
|
"slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
|
||||||
|
- slot, tsf, tsftu, intval, vif);
|
||||||
|
+ slot, tsf, tsftu / ATH_BCBUF, intval, vif);
|
||||||
|
|
||||||
|
bfaddr = 0;
|
||||||
|
if (vif) {
|
||||||
|
@@ -463,13 +458,17 @@ static void ath9k_beacon_init(struct ath
|
||||||
|
u32 next_beacon,
|
||||||
|
u32 beacon_period)
|
||||||
|
{
|
||||||
|
- if (beacon_period & ATH9K_BEACON_RESET_TSF)
|
||||||
|
+ if (sc->sc_flags & SC_OP_TSF_RESET) {
|
||||||
|
ath9k_ps_wakeup(sc);
|
||||||
|
+ ath9k_hw_reset_tsf(sc->sc_ah);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
|
||||||
|
|
||||||
|
- if (beacon_period & ATH9K_BEACON_RESET_TSF)
|
||||||
|
+ if (sc->sc_flags & SC_OP_TSF_RESET) {
|
||||||
|
ath9k_ps_restore(sc);
|
||||||
|
+ sc->sc_flags &= ~SC_OP_TSF_RESET;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -484,18 +483,14 @@ static void ath_beacon_config_ap(struct
|
||||||
|
u32 nexttbtt, intval;
|
||||||
|
|
||||||
|
/* NB: the beacon interval is kept internally in TU's */
|
||||||
|
- intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
|
||||||
|
+ intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD);
|
||||||
|
intval /= ATH_BCBUF; /* for staggered beacons */
|
||||||
|
nexttbtt = intval;
|
||||||
|
|
||||||
|
- if (sc->sc_flags & SC_OP_TSF_RESET)
|
||||||
|
- intval |= ATH9K_BEACON_RESET_TSF;
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* In AP mode we enable the beacon timers and SWBA interrupts to
|
||||||
|
* prepare beacon frames.
|
||||||
|
*/
|
||||||
|
- intval |= ATH9K_BEACON_ENA;
|
||||||
|
ah->imask |= ATH9K_INT_SWBA;
|
||||||
|
ath_beaconq_config(sc);
|
||||||
|
|
||||||
|
@@ -505,11 +500,6 @@ static void ath_beacon_config_ap(struct
|
||||||
|
ath9k_beacon_init(sc, nexttbtt, intval);
|
||||||
|
sc->beacon.bmisscnt = 0;
|
||||||
|
ath9k_hw_set_interrupts(ah, ah->imask);
|
||||||
|
-
|
||||||
|
- /* Clear the reset TSF flag, so that subsequent beacon updation
|
||||||
|
- will not reset the HW TSF. */
|
||||||
|
-
|
||||||
|
- sc->sc_flags &= ~SC_OP_TSF_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -643,25 +633,20 @@ static void ath_beacon_config_adhoc(stru
|
||||||
|
{
|
||||||
|
struct ath_hw *ah = sc->sc_ah;
|
||||||
|
struct ath_common *common = ath9k_hw_common(ah);
|
||||||
|
- u64 tsf;
|
||||||
|
- u32 tsftu, intval, nexttbtt;
|
||||||
|
-
|
||||||
|
- intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
|
||||||
|
-
|
||||||
|
+ u32 tsf, delta, intval, nexttbtt;
|
||||||
|
|
||||||
|
- /* Pull nexttbtt forward to reflect the current TSF */
|
||||||
|
+ tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE);
|
||||||
|
+ intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD);
|
||||||
|
|
||||||
|
- 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(ah);
|
||||||
|
- tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE;
|
||||||
|
- do {
|
||||||
|
- nexttbtt += intval;
|
||||||
|
- } while (nexttbtt < tsftu);
|
||||||
|
+ if (!sc->beacon.bc_tstamp)
|
||||||
|
+ nexttbtt = tsf + intval;
|
||||||
|
+ else {
|
||||||
|
+ if (tsf > sc->beacon.bc_tstamp)
|
||||||
|
+ delta = (tsf - sc->beacon.bc_tstamp);
|
||||||
|
+ else
|
||||||
|
+ delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp));
|
||||||
|
+ nexttbtt = tsf + roundup(delta, intval);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
ath_dbg(common, ATH_DBG_BEACON,
|
||||||
|
"IBSS nexttbtt %u intval %u (%u)\n",
|
||||||
|
@@ -672,7 +657,6 @@ static void ath_beacon_config_adhoc(stru
|
||||||
|
* 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;
|
||||||
|
ah->imask |= ATH9K_INT_SWBA;
|
||||||
|
|
||||||
|
ath_beaconq_config(sc);
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
|
@@ -1706,21 +1706,15 @@ void ath9k_hw_beaconinit(struct ath_hw *
|
||||||
|
case NL80211_IFTYPE_MESH_POINT:
|
||||||
|
REG_SET_BIT(ah, AR_TXCFG,
|
||||||
|
AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
|
||||||
|
- REG_WRITE(ah, AR_NEXT_NDP_TIMER,
|
||||||
|
- TU_TO_USEC(next_beacon +
|
||||||
|
- (ah->atim_window ? ah->
|
||||||
|
- atim_window : 1)));
|
||||||
|
+ REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon +
|
||||||
|
+ TU_TO_USEC(ah->atim_window ? ah->atim_window : 1));
|
||||||
|
flags |= AR_NDP_TIMER_EN;
|
||||||
|
case NL80211_IFTYPE_AP:
|
||||||
|
- REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
|
||||||
|
- REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,
|
||||||
|
- TU_TO_USEC(next_beacon -
|
||||||
|
- ah->config.
|
||||||
|
- dma_beacon_response_time));
|
||||||
|
- REG_WRITE(ah, AR_NEXT_SWBA,
|
||||||
|
- TU_TO_USEC(next_beacon -
|
||||||
|
- ah->config.
|
||||||
|
- sw_beacon_response_time));
|
||||||
|
+ REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon);
|
||||||
|
+ REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon -
|
||||||
|
+ TU_TO_USEC(ah->config.dma_beacon_response_time));
|
||||||
|
+ REG_WRITE(ah, AR_NEXT_SWBA, next_beacon -
|
||||||
|
+ TU_TO_USEC(ah->config.sw_beacon_response_time));
|
||||||
|
flags |=
|
||||||
|
AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
|
||||||
|
break;
|
||||||
|
@@ -1732,18 +1726,13 @@ void ath9k_hw_beaconinit(struct ath_hw *
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
- REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period));
|
||||||
|
- REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period));
|
||||||
|
- REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period));
|
||||||
|
- REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period));
|
||||||
|
+ REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period);
|
||||||
|
+ REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period);
|
||||||
|
+ REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period);
|
||||||
|
+ REG_WRITE(ah, AR_NDP_PERIOD, beacon_period);
|
||||||
|
|
||||||
|
REGWRITE_BUFFER_FLUSH(ah);
|
||||||
|
|
||||||
|
- beacon_period &= ~ATH9K_BEACON_ENA;
|
||||||
|
- if (beacon_period & ATH9K_BEACON_RESET_TSF) {
|
||||||
|
- ath9k_hw_reset_tsf(ah);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
REG_SET_BIT(ah, AR_TIMER_MODE, flags);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ath9k_hw_beaconinit);
|
||||||
|
@@ -2404,10 +2393,11 @@ static u32 rightmost_index(struct ath_ge
|
||||||
|
return timer_table->gen_timer_index[b];
|
||||||
|
}
|
||||||
|
|
||||||
|
-static u32 ath9k_hw_gettsf32(struct ath_hw *ah)
|
||||||
|
+u32 ath9k_hw_gettsf32(struct ath_hw *ah)
|
||||||
|
{
|
||||||
|
return REG_READ(ah, AR_TSF_L32);
|
||||||
|
}
|
||||||
|
+EXPORT_SYMBOL(ath9k_hw_gettsf32);
|
||||||
|
|
||||||
|
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
|
||||||
|
void (*trigger)(void *),
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||||
|
@@ -392,7 +392,7 @@ struct ath_beacon {
|
||||||
|
u32 beaconq;
|
||||||
|
u32 bmisscnt;
|
||||||
|
u32 ast_be_xmit;
|
||||||
|
- u64 bc_tstamp;
|
||||||
|
+ u32 bc_tstamp;
|
||||||
|
struct ieee80211_vif *bslot[ATH_BCBUF];
|
||||||
|
int slottime;
|
||||||
|
int slotupdate;
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/hw.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/hw.h
|
||||||
|
@@ -412,8 +412,6 @@ struct ath9k_beacon_state {
|
||||||
|
u32 bs_nextdtim;
|
||||||
|
u32 bs_intval;
|
||||||
|
#define ATH9K_BEACON_PERIOD 0x0000ffff
|
||||||
|
-#define ATH9K_BEACON_ENA 0x00800000
|
||||||
|
-#define ATH9K_BEACON_RESET_TSF 0x01000000
|
||||||
|
#define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */
|
||||||
|
u32 bs_dtimperiod;
|
||||||
|
u16 bs_cfpperiod;
|
||||||
|
@@ -927,6 +925,7 @@ void ath9k_hw_setopmode(struct ath_hw *a
|
||||||
|
void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
|
||||||
|
void ath9k_hw_setbssidmask(struct ath_hw *ah);
|
||||||
|
void ath9k_hw_write_associd(struct ath_hw *ah);
|
||||||
|
+u32 ath9k_hw_gettsf32(struct ath_hw *ah);
|
||||||
|
u64 ath9k_hw_gettsf64(struct ath_hw *ah);
|
||||||
|
void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
|
||||||
|
void ath9k_hw_reset_tsf(struct ath_hw *ah);
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
|
||||||
|
@@ -155,7 +155,7 @@ static void ath9k_htc_beacon_config_ap(s
|
||||||
|
nexttbtt = intval;
|
||||||
|
|
||||||
|
if (priv->op_flags & OP_TSF_RESET) {
|
||||||
|
- intval |= ATH9K_BEACON_RESET_TSF;
|
||||||
|
+ ath9k_hw_reset_tsf(priv->ah);
|
||||||
|
priv->op_flags &= ~OP_TSF_RESET;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
@@ -168,8 +168,6 @@ static void ath9k_htc_beacon_config_ap(s
|
||||||
|
} while (nexttbtt < tsftu);
|
||||||
|
}
|
||||||
|
|
||||||
|
- intval |= ATH9K_BEACON_ENA;
|
||||||
|
-
|
||||||
|
if (priv->op_flags & OP_ENABLE_BEACON)
|
||||||
|
imask |= ATH9K_INT_SWBA;
|
||||||
|
|
||||||
|
@@ -178,7 +176,7 @@ static void ath9k_htc_beacon_config_ap(s
|
||||||
|
bss_conf->beacon_interval, nexttbtt, imask);
|
||||||
|
|
||||||
|
WMI_CMD(WMI_DISABLE_INTR_CMDID);
|
||||||
|
- ath9k_hw_beaconinit(priv->ah, nexttbtt, intval);
|
||||||
|
+ ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
|
||||||
|
priv->bmiss_cnt = 0;
|
||||||
|
htc_imask = cpu_to_be32(imask);
|
||||||
|
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
|
||||||
|
@@ -207,7 +205,6 @@ static void ath9k_htc_beacon_config_adho
|
||||||
|
nexttbtt += intval;
|
||||||
|
} while (nexttbtt < tsftu);
|
||||||
|
|
||||||
|
- intval |= ATH9K_BEACON_ENA;
|
||||||
|
if (priv->op_flags & OP_ENABLE_BEACON)
|
||||||
|
imask |= ATH9K_INT_SWBA;
|
||||||
|
|
||||||
|
@@ -216,7 +213,7 @@ static void ath9k_htc_beacon_config_adho
|
||||||
|
bss_conf->beacon_interval, nexttbtt, imask);
|
||||||
|
|
||||||
|
WMI_CMD(WMI_DISABLE_INTR_CMDID);
|
||||||
|
- ath9k_hw_beaconinit(priv->ah, nexttbtt, intval);
|
||||||
|
+ ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
|
||||||
|
priv->bmiss_cnt = 0;
|
||||||
|
htc_imask = cpu_to_be32(imask);
|
||||||
|
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
|
Loading…
Reference in a new issue