mirror of
https://github.com/proski/madwifi
synced 2024-11-22 06:21:47 +03:00
IBSS ATIM window fixes
due to unlucky timing of beacon timer configuration (which we try to avoid) and due to unlucky timing of local TSF updates (triggered by the reception of a beacon with the same BSSID - something we can't avoid) the beacon timers (we have 4) can be updated seperately, leaving one of them in the past, not beeing updated until the timers wrap around. due to the fact that the beacon interval does not fit into the timer period (16 bit) a whole number of times the size of the ATIM window can get bigger than desired (we don't use ATIM right now so the window size should always be 1). this results in a phaenome described as "ramping" (ticket #1154) which is actually a transmission delay, since the hardware is not allowed to transmit data in the ATIM period. the problem is described and discussed in length at http://thread.gmane.org/gmane.linux.drivers.madwifi.devel/6066 since we don't know of a way to disable ATIM alltogether, the following adds some workarounds to this problem: 1.) disable interrupts in timing critical function ath_beacon_config 2.) stop beacons before reconfiguring them 3.) check ATIM window after critical code which might have changed the timers 3a.) beacon configuration 3b.) reception of a beacon with the same BSSID. the hardware will have updated the local TSF and this might have left one of the beacon timers in the past. git-svn-id: http://madwifi-project.org/svn/madwifi/trunk@3867 0192ed92-7a03-0410-a25b-9323aeb14dbd
This commit is contained in:
parent
ea9d467903
commit
b327291039
25
ath/if_ath.c
25
ath/if_ath.c
@ -5388,12 +5388,16 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
|
||||
u_int32_t tsftu, hw_tsftu;
|
||||
u_int32_t intval, nexttbtt = 0;
|
||||
int reset_tsf = 0;
|
||||
unsigned long irqstate;
|
||||
|
||||
if (vap == NULL)
|
||||
vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */
|
||||
|
||||
ni = vap->iv_bss;
|
||||
|
||||
/* TSF calculation is timing critical - we don't want to be interrupted here */
|
||||
local_irq_save(irqstate);
|
||||
|
||||
hw_tsf = ath_hal_gettsf64(ah);
|
||||
tsf = le64_to_cpu(ni->ni_tstamp.tsf);
|
||||
hw_tsftu = IEEE80211_TSF_TO_TU(hw_tsf);
|
||||
@ -5569,15 +5573,28 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
|
||||
~(HAL_BEACON_RESET_TSF | HAL_BEACON_ENA));
|
||||
#endif
|
||||
sc->sc_nexttbtt = nexttbtt;
|
||||
|
||||
/* stop beacons before reconfiguring the timers to avoid race
|
||||
* conditions. ath_hal_beaconinit will start them again */
|
||||
ath_hw_beacon_stop(sc);
|
||||
|
||||
ath_hal_beaconinit(ah, nexttbtt, intval);
|
||||
if (intval & HAL_BEACON_RESET_TSF) {
|
||||
sc->sc_last_tsf = 0;
|
||||
}
|
||||
sc->sc_bmisscount = 0;
|
||||
ath_hal_intrset(ah, sc->sc_imask);
|
||||
|
||||
if (ath_hw_check_atim(sc, 1, intval & HAL_BEACON_PERIOD)) {
|
||||
DPRINTF(sc, ATH_DEBUG_BEACON,
|
||||
"fixed atim window after beacon init\n");
|
||||
}
|
||||
}
|
||||
|
||||
ath_beacon_config_debug:
|
||||
|
||||
local_irq_restore(irqstate);
|
||||
|
||||
/* We print all debug messages here, in order to preserve the
|
||||
* time critical aspect of this function. */
|
||||
DPRINTF(sc, ATH_DEBUG_BEACON,
|
||||
@ -6327,6 +6344,14 @@ ath_recv_mgmt(struct ieee80211vap * vap, struct ieee80211_node *ni_or_null,
|
||||
DPRINTF(sc, ATH_DEBUG_BEACON,
|
||||
"Updated beacon timers\n");
|
||||
}
|
||||
|
||||
if (IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid)) {
|
||||
if (ath_hw_check_atim(sc, 1, vap->iv_bss->ni_intval)) {
|
||||
DPRINTF(sc, ATH_DEBUG_BEACON,
|
||||
"fixed atim window after beacon recv\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* NB: Fall Through */
|
||||
case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
|
||||
if (vap->iv_opmode == IEEE80211_M_IBSS &&
|
||||
|
@ -161,3 +161,72 @@ ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val)
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ath_hw_beacon_stop(struct ath_softc *sc) {
|
||||
HAL_BEACON_TIMERS btimers;
|
||||
|
||||
btimers.bt_intval = 0;
|
||||
btimers.bt_nexttbtt = 0;
|
||||
btimers.bt_nextdba = 0xffffffff;
|
||||
btimers.bt_nextswba = 0xffffffff;
|
||||
btimers.bt_nextatim = 0;
|
||||
|
||||
ath_hal_setbeacontimers(sc->sc_ah, &btimers);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IBSS mode: check the ATIM window size and fix it if necessary.
|
||||
*
|
||||
* the need for this function arises from the problem that due to unlucky timing
|
||||
* of beacon timer configuration (which we try to avoid) and due to unlucky
|
||||
* timing of local TSF updates (triggered by the reception of a beacon with the
|
||||
* same BSSID - something we can't avoid) the beacon timers can be up updated
|
||||
* seperately, leaving one of them in the past, not beeing updated until the
|
||||
* timers wrap around. due to the fact that the beacon interval does not fit
|
||||
* into the timer period (16 bit) a whole number of times the size of the ATIM
|
||||
* window can get bigger than desired.
|
||||
*
|
||||
* usually we have an ATIM window size of 1 but this function is written to
|
||||
* handle other window sizes as well.
|
||||
*/
|
||||
int
|
||||
ath_hw_check_atim(struct ath_softc *sc, int window, int intval)
|
||||
{
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
unsigned int nbtt, atim, is5210 = 0;
|
||||
|
||||
if (ATH_SREV_FROM_AH(ah) >= AR5K_SREV_VER_AR5416)
|
||||
return 0; /* AR5416+ doesn't do ATIM in HW */
|
||||
|
||||
if (ATH_SREV_FROM_AH(ah) == AR5K_SREV_VER_AR5210) {
|
||||
nbtt = OS_REG_READ(ah, AR5K_TIMER0_5210);
|
||||
atim = OS_REG_READ(ah, AR5K_TIMER3_5210);
|
||||
is5210 = 1;
|
||||
}
|
||||
else {
|
||||
nbtt = OS_REG_READ(ah, AR5K_TIMER0_5211);
|
||||
atim = OS_REG_READ(ah, AR5K_TIMER3_5211);
|
||||
}
|
||||
|
||||
/*
|
||||
* check if the ATIM window is still correct:
|
||||
* 1.) usually ATIM should be NBTT + window
|
||||
* 2.) nbtt already updated
|
||||
* 3.) nbtt already updated and has wrapped around
|
||||
* 4.) atim has wrapped around
|
||||
*/
|
||||
if ((atim - nbtt != window) && /* 1.) */
|
||||
(nbtt - atim != intval - window) && /* 2.) */
|
||||
((nbtt | 0x10000) - atim != intval - window) && /* 3.) */
|
||||
((atim | 0x10000) - nbtt != window)) { /* 4.) */
|
||||
if (is5210)
|
||||
OS_REG_WRITE(ah, AR5K_TIMER3_5210, nbtt + window );
|
||||
else
|
||||
OS_REG_WRITE(ah, AR5K_TIMER3_5211, nbtt + window );
|
||||
return atim - nbtt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -176,6 +176,35 @@
|
||||
#define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mbit/s for ACK/CTS (?) */
|
||||
#define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate (for ACK/CTS ?) [5211+] */
|
||||
|
||||
/*
|
||||
* PCU beacon control register
|
||||
*/
|
||||
#define AR5K_BEACON_5210 0x8024
|
||||
#define AR5K_BEACON_5211 0x8020
|
||||
|
||||
/*
|
||||
* Next beacon time register
|
||||
*/
|
||||
#define AR5K_TIMER0_5210 0x802c
|
||||
#define AR5K_TIMER0_5211 0x8028
|
||||
/*
|
||||
* Next DMA beacon alert register
|
||||
*/
|
||||
#define AR5K_TIMER1_5210 0x8030
|
||||
#define AR5K_TIMER1_5211 0x802c
|
||||
|
||||
/*
|
||||
* Next software beacon alert register
|
||||
*/
|
||||
#define AR5K_TIMER2_5210 0x8034
|
||||
#define AR5K_TIMER2_5211 0x8030
|
||||
|
||||
/*
|
||||
* Next ATIM window time register
|
||||
*/
|
||||
#define AR5K_TIMER3_5210 0x8038
|
||||
#define AR5K_TIMER3_5211 0x8034
|
||||
|
||||
|
||||
enum ath5k_srev_type {
|
||||
AR5K_VERSION_VER,
|
||||
@ -241,6 +270,8 @@ enum ath5k_dmasize {
|
||||
int ath_set_ack_bitrate(struct ath_softc *sc, int);
|
||||
int ar_device(int devid);
|
||||
const char * ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
|
||||
void ath_hw_beacon_stop(struct ath_softc *sc);
|
||||
int ath_hw_check_atim(struct ath_softc *sc, int window, int intval);
|
||||
|
||||
static inline unsigned long field_width(unsigned long mask, unsigned long shift)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user