From fc4de9b7fcbfc6729ca663011d583374eda15751 Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Thu, 8 Sep 2011 01:23:05 +0000 Subject: [PATCH] Update the TSF and next-TBTT methods to work for the AR5416 and later NICs. This is another commit in a series of TDMA support fixes for the 11n NICs. * Move ath_hal_getnexttbtt() into the HAL; write methods for it. This returns a timer value in TSF, rather than TU. * Move ath_hal_getcca() and ath_hal_setcca() into the HAL too, where they likely now belong. * Create a new HAL capability: HAL_CAP_LONG_RXDESC_TSF. The pre-11n NICs write 15 bit TSF snapshots into the RX descriptor; the AR5416 and later write 32 bit TSF snapshots into the RX descriptor. * Use the new capability to choose between 15 and 31 bit TSF adjustment functions in ath_extend_tsf(). * Write ar5416GetTsf64() and ar5416SetTsf64() methods. ar5416GetTsf64() tries to compensate for TSF changes at the 32 bit boundary. According to yin, this fixes the TDMA beaconing on 11n chipsets and TDMA stations can now associate/talk, but there are still issues with traffic stability which need to be investigated. The ath_hal_extendtsf() function is also used in RX packet timestamping; this may improve adhoc mode on the 11n chipsets. It also will affect the timestamps seen in radiotap frames. Submitted by: Kang Yin Su Approved by: re (kib) --- sys/dev/ath/ath_hal/ah.c | 36 ++++++++ sys/dev/ath/ath_hal/ah.h | 18 ++++ sys/dev/ath/ath_hal/ah_internal.h | 3 +- sys/dev/ath/ath_hal/ar5210/ar5210.h | 1 + sys/dev/ath/ath_hal/ar5210/ar5210_attach.c | 1 + sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c | 11 +++ sys/dev/ath/ath_hal/ar5211/ar5211.h | 1 + sys/dev/ath/ath_hal/ar5211/ar5211_attach.c | 1 + sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c | 11 +++ sys/dev/ath/ath_hal/ar5212/ar5212.h | 1 + sys/dev/ath/ath_hal/ar5212/ar5212_attach.c | 1 + sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c | 11 +++ sys/dev/ath/ath_hal/ar5416/ar5416.h | 3 + sys/dev/ath/ath_hal/ar5416/ar5416_attach.c | 4 + sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c | 9 ++ sys/dev/ath/ath_hal/ar5416/ar5416_misc.c | 35 ++++++++ sys/dev/ath/ath_hal/ar5416/ar5416_reset.c | 13 ++- sys/dev/ath/if_ath.c | 95 +++++++++++----------- sys/dev/ath/if_athvar.h | 7 +- 19 files changed, 207 insertions(+), 55 deletions(-) diff --git a/sys/dev/ath/ath_hal/ah.c b/sys/dev/ath/ath_hal/ah.c index 2739f97305a8..4055079dc71c 100644 --- a/sys/dev/ath/ath_hal/ah.c +++ b/sys/dev/ath/ath_hal/ah.c @@ -657,6 +657,8 @@ ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, } case HAL_CAP_RXDESC_SELFLINK: /* hardware supports self-linked final RX descriptors correctly */ return pCap->halHasRxSelfLinkedTail ? HAL_OK : HAL_ENOTSUPP; + case HAL_CAP_LONG_RXDESC_TSF: /* 32 bit TSF in RX descriptor? */ + return pCap->halHasLongRxDescTsf ? HAL_OK : HAL_ENOTSUPP; default: return HAL_EINVAL; } @@ -1222,3 +1224,37 @@ ath_ee_interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight, } return rv; } + +/* + * Adjust the TSF. + */ +void +ath_hal_adjusttsf(struct ath_hal *ah, int32_t tsfdelta) +{ + /* XXX handle wrap/overflow */ + OS_REG_WRITE(ah, AR_TSF_L32, OS_REG_READ(ah, AR_TSF_L32) + tsfdelta); +} + +/* + * Enable or disable CCA. + */ +void +ath_hal_setcca(struct ath_hal *ah, int ena) +{ + /* + * NB: fill me in; this is not provided by default because disabling + * CCA in most locales violates regulatory. + */ +} + +/* + * Get CCA setting. + */ +int +ath_hal_getcca(struct ath_hal *ah) +{ + u_int32_t diag; + if (ath_hal_getcapability(ah, HAL_CAP_DIAG, 0, &diag) != HAL_OK) + return 1; + return ((diag & 0x500000) == 0); +} diff --git a/sys/dev/ath/ath_hal/ah.h b/sys/dev/ath/ath_hal/ah.h index 05ac87d9f43d..f4254c14fa87 100644 --- a/sys/dev/ath/ath_hal/ah.h +++ b/sys/dev/ath/ath_hal/ah.h @@ -148,6 +148,7 @@ typedef enum { HAL_CAP_BSSIDMATCH = 238, /* hardware has disable bssid match */ HAL_CAP_STREAMS = 239, /* how many 802.11n spatial streams are available */ HAL_CAP_RXDESC_SELFLINK = 242, /* support a self-linked tail RX descriptor */ + HAL_CAP_LONG_RXDESC_TSF = 243, /* hardware supports 32bit TSF in RX descriptor */ } HAL_CAPABILITY_TYPE; /* @@ -996,6 +997,7 @@ struct ath_hal { void __ahdecl(*ah_setStationBeaconTimers)(struct ath_hal*, const HAL_BEACON_STATE *); void __ahdecl(*ah_resetStationBeaconTimers)(struct ath_hal*); + uint64_t __ahdecl(*ah_getNextTBTT)(struct ath_hal *); /* 802.11n Functions */ HAL_BOOL __ahdecl(*ah_chainTxDesc)(struct ath_hal *, @@ -1138,4 +1140,20 @@ extern uint32_t __ahdecl ath_computedur_ht(uint32_t frameLen, uint16_t rate, extern uint16_t __ahdecl ath_hal_computetxtime(struct ath_hal *, const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix, HAL_BOOL shortPreamble); + +/* + * Adjust the TSF. + */ +extern void __ahdecl ath_hal_adjusttsf(struct ath_hal *ah, int32_t tsfdelta); + +/* + * Enable or disable CCA. + */ +void __ahdecl ath_hal_setcca(struct ath_hal *ah, int ena); + +/* + * Get CCA setting. + */ +int __ahdecl ath_hal_getcca(struct ath_hal *ah); + #endif /* _ATH_AH_H_ */ diff --git a/sys/dev/ath/ath_hal/ah_internal.h b/sys/dev/ath/ath_hal/ah_internal.h index 28c88413f12c..79184bd23650 100644 --- a/sys/dev/ath/ath_hal/ah_internal.h +++ b/sys/dev/ath/ath_hal/ah_internal.h @@ -208,7 +208,8 @@ typedef struct { halBssidMatchSupport : 1, hal4kbSplitTransSupport : 1, halHasRxSelfLinkedTail : 1, - halSupportsFastClock5GHz : 1; /* Hardware supports 5ghz fast clock; check eeprom/channel before using */ + halSupportsFastClock5GHz : 1, /* Hardware supports 5ghz fast clock; check eeprom/channel before using */ + halHasLongRxDescTsf : 1; uint32_t halWirelessModes; uint16_t halTotalQueues; uint16_t halKeyCacheSize; diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210.h b/sys/dev/ath/ath_hal/ar5210/ar5210.h index a8776726a3ba..24718531566f 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210.h +++ b/sys/dev/ath/ath_hal/ar5210/ar5210.h @@ -268,6 +268,7 @@ extern void ar5210BeaconInit(struct ath_hal *, uint32_t, uint32_t); extern void ar5210SetStaBeaconTimers(struct ath_hal *, const HAL_BEACON_STATE *); extern void ar5210ResetStaBeaconTimers(struct ath_hal *); +extern uint64_t ar5210GetNextTBTT(struct ath_hal *); extern HAL_BOOL ar5210IsInterruptPending(struct ath_hal *); extern HAL_BOOL ar5210GetPendingInterrupts(struct ath_hal *, HAL_INT *); diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c index 41d957a614c6..79c305511e6f 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c @@ -148,6 +148,7 @@ static const struct ath_hal_private ar5210hal = {{ .ah_beaconInit = ar5210BeaconInit, .ah_setStationBeaconTimers = ar5210SetStaBeaconTimers, .ah_resetStationBeaconTimers = ar5210ResetStaBeaconTimers, + .ah_getNextTBTT = ar5210GetNextTBTT, /* Interrupt Functions */ .ah_isInterruptPending = ar5210IsInterruptPending, diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c b/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c index a613c9ca7d16..e12b039723e5 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c @@ -26,6 +26,17 @@ #include "ar5210/ar5210reg.h" #include "ar5210/ar5210desc.h" +/* + * Return the hardware NextTBTT in TSF + */ +uint64_t +ar5210GetNextTBTT(struct ath_hal *ah) +{ +#define TU_TO_TSF(_tu) (((uint64_t)(_tu)) << 10) + return TU_TO_TSF(OS_REG_READ(ah, AR_TIMER0)); +#undef TU_TO_TSF +} + /* * Initialize all of the hardware registers used to send beacons. */ diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211.h b/sys/dev/ath/ath_hal/ar5211/ar5211.h index 0057ba425f98..51acd38862c5 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211.h +++ b/sys/dev/ath/ath_hal/ar5211/ar5211.h @@ -296,6 +296,7 @@ extern void ar5211BeaconInit(struct ath_hal *, uint32_t, uint32_t); extern void ar5211SetStaBeaconTimers(struct ath_hal *, const HAL_BEACON_STATE *); extern void ar5211ResetStaBeaconTimers(struct ath_hal *); +extern uint64_t ar5211GetNextTBTT(struct ath_hal *); extern HAL_BOOL ar5211IsInterruptPending(struct ath_hal *); extern HAL_BOOL ar5211GetPendingInterrupts(struct ath_hal *, HAL_INT *); diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c index 14daa0bffedc..a0c42b2bf7c4 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c @@ -148,6 +148,7 @@ static const struct ath_hal_private ar5211hal = {{ .ah_beaconInit = ar5211BeaconInit, .ah_setStationBeaconTimers = ar5211SetStaBeaconTimers, .ah_resetStationBeaconTimers = ar5211ResetStaBeaconTimers, + .ah_getNextTBTT = ar5211GetNextTBTT, /* Interrupt Functions */ .ah_isInterruptPending = ar5211IsInterruptPending, diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c b/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c index 31e9c5df8a93..b2775d0376f5 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c @@ -29,6 +29,17 @@ * Routines used to initialize and generated beacons for the AR5211/AR5311. */ +/* + * Return the hardware NextTBTT in TSF + */ +uint64_t +ar5211GetNextTBTT(struct ath_hal *ah) +{ +#define TU_TO_TSF(_tu) (((uint64_t)(_tu)) << 10) + return TU_TO_TSF(OS_REG_READ(ah, AR_TIMER0)); +#undef TU_TO_TSF +} + /* * Initialize all of the hardware registers used to send beacons. */ diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212.h b/sys/dev/ath/ath_hal/ar5212/ar5212.h index b93ab11bb913..40e718e46736 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212.h +++ b/sys/dev/ath/ath_hal/ar5212/ar5212.h @@ -430,6 +430,7 @@ extern void ar5212BeaconInit(struct ath_hal *ah, extern void ar5212ResetStaBeaconTimers(struct ath_hal *ah); extern void ar5212SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *); +extern uint64_t ar5212GetNextTBTT(struct ath_hal *); extern HAL_BOOL ar5212IsInterruptPending(struct ath_hal *ah); extern HAL_BOOL ar5212GetPendingInterrupts(struct ath_hal *ah, HAL_INT *); diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c index fe48b2eb1ad0..eaceaba766e3 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c @@ -151,6 +151,7 @@ static const struct ath_hal_private ar5212hal = {{ .ah_beaconInit = ar5212BeaconInit, .ah_setStationBeaconTimers = ar5212SetStaBeaconTimers, .ah_resetStationBeaconTimers = ar5212ResetStaBeaconTimers, + .ah_getNextTBTT = ar5212GetNextTBTT, /* Interrupt Functions */ .ah_isInterruptPending = ar5212IsInterruptPending, diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c b/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c index bf0b38a56db7..1b4b342bc4ae 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c @@ -25,6 +25,17 @@ #include "ar5212/ar5212reg.h" #include "ar5212/ar5212desc.h" +/* + * Return the hardware NextTBTT in TSF + */ +uint64_t +ar5212GetNextTBTT(struct ath_hal *ah) +{ +#define TU_TO_TSF(_tu) (((uint64_t)(_tu)) << 10) + return TU_TO_TSF(OS_REG_READ(ah, AR_TIMER0)); +#undef TU_TO_TSF +} + /* * Initialize all of the hardware registers used to * send beacons. Note that for station operation the diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416.h b/sys/dev/ath/ath_hal/ar5416/ar5416.h index 522338240fbd..a0f5deead8bb 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416.h +++ b/sys/dev/ath/ath_hal/ar5416/ar5416.h @@ -169,6 +169,7 @@ extern void ar5416BeaconInit(struct ath_hal *ah, extern void ar5416ResetStaBeaconTimers(struct ath_hal *ah); extern void ar5416SetStaBeaconTimers(struct ath_hal *ah, const HAL_BEACON_STATE *); +extern uint64_t ar5416GetNextTBTT(struct ath_hal *); extern HAL_BOOL ar5416EepromRead(struct ath_hal *, u_int off, uint16_t *data); extern HAL_BOOL ar5416EepromWrite(struct ath_hal *, u_int off, uint16_t data); @@ -186,6 +187,8 @@ extern void ar5416GpioSetIntr(struct ath_hal *ah, u_int, uint32_t ilevel); extern u_int ar5416GetWirelessModes(struct ath_hal *ah); extern void ar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state); +extern uint64_t ar5416GetTsf64(struct ath_hal *ah); +extern void ar5416SetTsf64(struct ath_hal *ah, uint64_t tsf64); extern void ar5416ResetTsf(struct ath_hal *ah); extern HAL_BOOL ar5416SetAntennaSwitch(struct ath_hal *, HAL_ANT_SETTING); extern HAL_BOOL ar5416SetDecompMask(struct ath_hal *, uint16_t, int); diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c index 647d9d84da94..12589f28fff2 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c @@ -136,6 +136,7 @@ ar5416InitState(struct ath_hal_5416 *ahp5416, uint16_t devid, HAL_SOFTC sc, ah->ah_gpioGet = ar5416GpioGet; ah->ah_gpioSet = ar5416GpioSet; ah->ah_gpioSetIntr = ar5416GpioSetIntr; + ah->ah_getTsf64 = ar5416GetTsf64; ah->ah_resetTsf = ar5416ResetTsf; ah->ah_getRfGain = ar5416GetRfgain; ah->ah_setAntennaSwitch = ar5416SetAntennaSwitch; @@ -160,6 +161,7 @@ ar5416InitState(struct ath_hal_5416 *ahp5416, uint16_t devid, HAL_SOFTC sc, ah->ah_beaconInit = ar5416BeaconInit; ah->ah_setStationBeaconTimers = ar5416SetStaBeaconTimers; ah->ah_resetStationBeaconTimers = ar5416ResetStaBeaconTimers; + ah->ah_getNextTBTT = ar5416GetNextTBTT; /* 802.11n Functions */ ah->ah_chainTxDesc = ar5416ChainTxDesc; @@ -888,6 +890,8 @@ ar5416FillCapabilityInfo(struct ath_hal *ah) pCap->halGTTSupport = AH_TRUE; pCap->halCSTSupport = AH_TRUE; pCap->halEnhancedDfsSupport = AH_FALSE; + /* Hardware supports 32 bit TSF values in the RX descriptor */ + pCap->halHasLongRxDescTsf = AH_TRUE; if (ath_hal_eepromGetFlag(ah, AR_EEP_RFKILL) && ath_hal_eepromGet(ah, AR_EEP_RFSILENT, &ahpriv->ah_rfsilent) == HAL_OK) { diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c b/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c index 8a36cf557df6..8b61e14658ae 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c @@ -28,6 +28,15 @@ #define TU_TO_USEC(_tu) ((_tu) << 10) #define ONE_EIGHTH_TU_TO_USEC(_tu8) ((_tu8) << 7) +/* + * Return the hardware NextTBTT in TSF + */ +uint64_t +ar5416GetNextTBTT(struct ath_hal *ah) +{ + return OS_REG_READ(ah, AR_NEXT_TBTT); +} + /* * Initialize all of the hardware registers used to * send beacons. Note that for station operation the diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c b/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c index a0952f866965..7e61c84930d9 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c @@ -92,6 +92,41 @@ ar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state) OS_REG_WRITE(ah, AR_MAC_LED, bits); } +/* + * Get the current hardware tsf for stamlme + */ +uint64_t +ar5416GetTsf64(struct ath_hal *ah) +{ + uint32_t low1, low2, u32; + + /* sync multi-word read */ + low1 = OS_REG_READ(ah, AR_TSF_L32); + u32 = OS_REG_READ(ah, AR_TSF_U32); + low2 = OS_REG_READ(ah, AR_TSF_L32); + if (low2 < low1) { /* roll over */ + /* + * If we are not preempted this will work. If we are + * then we re-reading AR_TSF_U32 does no good as the + * low bits will be meaningless. Likewise reading + * L32, U32, U32, then comparing the last two reads + * to check for rollover doesn't help if preempted--so + * we take this approach as it costs one less PCI read + * which can be noticeable when doing things like + * timestamping packets in monitor mode. + */ + u32++; + } + return (((uint64_t) u32) << 32) | ((uint64_t) low2); +} + +void +ar5416SetTsf64(struct ath_hal *ah, uint64_t tsf64) +{ + OS_REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff); + OS_REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff); +} + /* * Reset the current hardware tsf for stamlme. */ diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c b/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c index c21692eca33e..112d9669540f 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_reset.c @@ -147,7 +147,7 @@ ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode, /* For chips on which the RTC reset is done, save TSF before it gets cleared */ if (AR_SREV_HOWL(ah) || (AR_SREV_MERLIN(ah) && ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL))) - tsf = ar5212GetTsf64(ah); + tsf = ar5416GetTsf64(ah); /* Mark PHY as inactive; marked active in ar5416InitBB() */ ar5416MarkPhyInactive(ah); @@ -159,7 +159,7 @@ ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode, /* Restore TSF */ if (tsf) - ar5212SetTsf64(ah, tsf); + ar5416SetTsf64(ah, tsf); OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); if (AR_SREV_MERLIN_10_OR_LATER(ah)) @@ -192,9 +192,9 @@ ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode, * value after the initvals have been applied, with an offset * based on measured time difference */ - if (AR_SREV_HOWL(ah) && (ar5212GetTsf64(ah) < tsf)) { + if (AR_SREV_HOWL(ah) && (ar5416GetTsf64(ah) < tsf)) { tsf += 1500; - ar5212SetTsf64(ah, tsf); + ar5416SetTsf64(ah, tsf); } HALDEBUG(ah, HAL_DEBUG_RESET, ">>>2 %s: AR_PHY_DAG_CTRLCCK=0x%x\n", @@ -364,8 +364,7 @@ ar5416Reset(struct ath_hal *ah, HAL_OPMODE opmode, OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, 300); OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, 750); -#endif - +#endif ar5416InitBB(ah, chan); /* Setup compression registers */ @@ -503,7 +502,7 @@ ar5416ChannelChange(struct ath_hal *ah, const structu ieee80211_channel *chan) chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; ichan->channel_time = 0; - ichan->tsf_last = ar5212GetTsf64(ah); + ichan->tsf_last = ar5416GetTsf64(ah); ar5212TxEnable(ah, AH_TRUE); return AH_TRUE; } diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index a717323ca2d2..af612748f8c2 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -214,24 +214,6 @@ static void ath_tdma_update(struct ieee80211_node *ni, static void ath_tdma_beacon_send(struct ath_softc *sc, struct ieee80211vap *vap); -static __inline void -ath_hal_setcca(struct ath_hal *ah, int ena) -{ - /* - * NB: fill me in; this is not provided by default because disabling - * CCA in most locales violates regulatory. - */ -} - -static __inline int -ath_hal_getcca(struct ath_hal *ah) -{ - u_int32_t diag; - if (ath_hal_getcapability(ah, HAL_CAP_DIAG, 0, &diag) != HAL_OK) - return 1; - return ((diag & 0x500000) == 0); -} - #define TDMA_EP_MULTIPLIER (1<<10) /* pow2 to optimize out * and / */ #define TDMA_LPF_LEN 6 #define TDMA_DUMMY_MARKER 0x127 @@ -613,6 +595,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) sc->sc_hasbmatch = ath_hal_hasbssidmatch(ah); sc->sc_hastsfadd = ath_hal_hastsfadjust(ah); sc->sc_rxslink = ath_hal_self_linked_final_rxdesc(ah); + sc->sc_rxtsf32 = ath_hal_has_long_rxdesc_tsf(ah); if (ath_hal_hasfastframes(ah)) ic->ic_caps |= IEEE80211_C_FF; wmodes = ath_hal_getwirelessmodes(ah); @@ -3294,13 +3277,48 @@ ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) * a full 64-bit TSF using the specified TSF. */ static __inline u_int64_t -ath_extend_tsf(u_int32_t rstamp, u_int64_t tsf) +ath_extend_tsf15(u_int32_t rstamp, u_int64_t tsf) { if ((tsf & 0x7fff) < rstamp) tsf -= 0x8000; + return ((tsf &~ 0x7fff) | rstamp); } +/* + * Extend 32-bit time stamp from rx descriptor to + * a full 64-bit TSF using the specified TSF. + */ +static __inline u_int64_t +ath_extend_tsf32(u_int32_t rstamp, u_int64_t tsf) +{ + u_int32_t tsf_low = tsf & 0xffffffff; + u_int64_t tsf64 = (tsf & ~0xffffffffULL) | rstamp; + + if (rstamp > tsf_low && (rstamp - tsf_low > 0x10000000)) + tsf64 -= 0x100000000ULL; + + if (rstamp < tsf_low && (tsf_low - rstamp > 0x10000000)) + tsf64 += 0x100000000ULL; + + return tsf64; +} + +/* + * Extend the TSF from the RX descriptor to a full 64 bit TSF. + * Earlier hardware versions only wrote the low 15 bits of the + * TSF into the RX descriptor; later versions (AR5416 and up) + * include the 32 bit TSF value. + */ +static __inline u_int64_t +ath_extend_tsf(struct ath_softc *sc, u_int32_t rstamp, u_int64_t tsf) +{ + if (sc->sc_rxtsf32) + return ath_extend_tsf32(rstamp, tsf); + else + return ath_extend_tsf15(rstamp, tsf); +} + /* * Intercept management frames to collect beacon rssi data * and to do ibss merges. @@ -3334,7 +3352,7 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, if (vap->iv_opmode == IEEE80211_M_IBSS && vap->iv_state == IEEE80211_S_RUN) { uint32_t rstamp = sc->sc_lastrs->rs_tstamp; - uint64_t tsf = ath_extend_tsf(rstamp, + uint64_t tsf = ath_extend_tsf(sc, rstamp, ath_hal_gettsf64(sc->sc_ah)); /* * Handle ibss merge as needed; check the tsf on the @@ -3406,7 +3424,7 @@ ath_rx_tap(struct ifnet *ifp, struct mbuf *m, sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTGI; } #endif - sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(rs->rs_tstamp, tsf)); + sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(sc, rs->rs_tstamp, tsf)); if (rs->rs_status & HAL_RXERR_CRC) sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; /* XXX propagate other error flags from descriptor */ @@ -5460,20 +5478,6 @@ ath_announce(struct ath_softc *sc) } #ifdef IEEE80211_SUPPORT_TDMA -static __inline uint32_t -ath_hal_getnexttbtt(struct ath_hal *ah) -{ -#define AR_TIMER0 0x8028 - return OS_REG_READ(ah, AR_TIMER0); -} - -static __inline void -ath_hal_adjusttsf(struct ath_hal *ah, int32_t tsfdelta) -{ - /* XXX handle wrap/overflow */ - OS_REG_WRITE(ah, AR_TSF_L32, OS_REG_READ(ah, AR_TSF_L32) + tsfdelta); -} - static void ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt, u_int32_t bintval) { @@ -5629,8 +5633,8 @@ ath_tdma_update(struct ieee80211_node *ni, struct ath_softc *sc = ic->ic_ifp->if_softc; struct ath_hal *ah = sc->sc_ah; const HAL_RATE_TABLE *rt = sc->sc_currates; - u_int64_t tsf, rstamp, nextslot; - u_int32_t txtime, nextslottu, timer0; + u_int64_t tsf, rstamp, nextslot, nexttbtt; + u_int32_t txtime, nextslottu; int32_t tudelta, tsfdelta; const struct ath_rx_status *rs; int rix; @@ -5661,7 +5665,7 @@ ath_tdma_update(struct ieee80211_node *ni, /* extend rx timestamp to 64 bits */ rs = sc->sc_lastrs; tsf = ath_hal_gettsf64(ah); - rstamp = ath_extend_tsf(rs->rs_tstamp, tsf); + rstamp = ath_extend_tsf(sc, rs->rs_tstamp, tsf); /* * The rx timestamp is set by the hardware on completing * reception (at the point where the rx descriptor is DMA'd @@ -5677,15 +5681,15 @@ ath_tdma_update(struct ieee80211_node *ni, nextslottu = TSF_TO_TU(nextslot>>32, nextslot) & HAL_BEACON_PERIOD; /* - * TIMER0 is the h/w's idea of NextTBTT (in TU's). Convert - * to usecs and calculate the difference between what the + * Retrieve the hardware NextTBTT in usecs + * and calculate the difference between what the * other station thinks and what we have programmed. This * lets us figure how to adjust our timers to match. The * adjustments are done by pulling the TSF forward and possibly * rewriting the beacon timers. */ - timer0 = ath_hal_getnexttbtt(ah); - tsfdelta = (int32_t)((nextslot % TU_TO_TSF(HAL_BEACON_PERIOD+1)) - TU_TO_TSF(timer0)); + nexttbtt = ath_hal_getnexttbtt(ah); + tsfdelta = (int32_t)((nextslot % TU_TO_TSF(HAL_BEACON_PERIOD + 1)) - nexttbtt); DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, "tsfdelta %d avg +%d/-%d\n", tsfdelta, @@ -5705,7 +5709,7 @@ ath_tdma_update(struct ieee80211_node *ni, TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0); TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0); } - tudelta = nextslottu - timer0; + tudelta = nextslottu - TSF_TO_TU(nexttbtt >> 32, nexttbtt); /* * Copy sender's timetstamp into tdma ie so they can @@ -5724,10 +5728,9 @@ ath_tdma_update(struct ieee80211_node *ni, &ni->ni_tstamp.data, 8); #if 0 DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, - "tsf %llu nextslot %llu (%d, %d) nextslottu %u timer0 %u (%d)\n", + "tsf %llu nextslot %llu (%d, %d) nextslottu %u nexttbtt %llu (%d)\n", (unsigned long long) tsf, (unsigned long long) nextslot, - (int)(nextslot - tsf), tsfdelta, - nextslottu, timer0, tudelta); + (int)(nextslot - tsf), tsfdelta, nextslottu, nexttbtt, tudelta); #endif /* * Adjust the beacon timers only when pulling them forward diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 5baa4ebd9401..5c468e7f7646 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -255,7 +255,8 @@ struct ath_softc { sc_setcca : 1,/* set/clr CCA with TDMA */ sc_resetcal : 1,/* reset cal state next trip */ sc_rxslink : 1,/* do self-linked final descriptor */ - sc_kickpcu : 1;/* kick PCU RX on next RX proc */ + sc_kickpcu : 1,/* kick PCU RX on next RX proc */ + sc_rxtsf32 : 1;/* RX dec TSF is 32 bits */ uint32_t sc_eerd; /* regdomain from EEPROM */ uint32_t sc_eecc; /* country code from EEPROM */ /* rate tables */ @@ -482,6 +483,8 @@ void ath_intr(void *); ((*(_ah)->ah_setBeaconTimers)((_ah), (_bt))) #define ath_hal_beacontimers(_ah, _bs) \ ((*(_ah)->ah_setStationBeaconTimers)((_ah), (_bs))) +#define ath_hal_getnexttbtt(_ah) \ + ((*(_ah)->ah_getNextTBTT)((_ah))) #define ath_hal_setassocid(_ah, _bss, _associd) \ ((*(_ah)->ah_writeAssocid)((_ah), (_bss), (_associd))) #define ath_hal_phydisable(_ah) \ @@ -657,6 +660,8 @@ void ath_intr(void *); (ath_hal_getcapability(_ah, HAL_CAP_RXDESC_SELFLINK, 0, NULL) == HAL_OK) #define ath_hal_gtxto_supported(_ah) \ (ath_hal_getcapability(_ah, HAL_CAP_GTXTO, 0, NULL) == HAL_OK) +#define ath_hal_has_long_rxdesc_tsf(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_LONG_RXDESC_TSF, 0, NULL) == HAL_OK) #define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \ ((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq)))