Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 7 Sep 2011 09:16:44 +0800
From:      Adrian Chadd <adrian@freebsd.org>
To:        Yin <paradyse@gmail.com>
Cc:        freebsd-wireless@freebsd.org
Subject:   [patch] Fix TBTT, TSF handling for TDMA on AR5416 and later chips
Message-ID:  <CAJ-Vmok9n3Gh-Uiuaqh8Q6XOgOkeg_sKBKh1MqVXMQTkNTm42A@mail.gmail.com>

next in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Hi Yin, all;

I've done a bit of tidying up of Yin's TDMA related cleanups.

In particular, I've added a new capability (HAL_CAP_LONG_RXDESC_TSF)
which the AR5416 and later chips set. This indicates the received TSF
is 32 bits rather than 15 bits.

Yin, would you mind testing this in your local setup and make sure it
works the same as your patch? I'll submit it for inclusion into -HEAD
/ 9.0 if it does.

Thanks again for your great work!



adrian

[-- Attachment #2 --]
Index: sys/dev/ath/if_athvar.h
===================================================================
--- sys/dev/ath/if_athvar.h	(revision 225143)
+++ sys/dev/ath/if_athvar.h	(working copy)
@@ -255,7 +255,8 @@
 				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 @@
 	((*(_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 @@
 	(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)))
Index: sys/dev/ath/ath_hal/ar5416/ar5416_attach.c
===================================================================
--- sys/dev/ath/ath_hal/ar5416/ar5416_attach.c	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5416/ar5416_attach.c	(working copy)
@@ -136,6 +136,7 @@
 	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 @@
 	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 @@
 	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) {
Index: sys/dev/ath/ath_hal/ar5416/ar5416_reset.c
===================================================================
--- sys/dev/ath/ath_hal/ar5416/ar5416_reset.c	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5416/ar5416_reset.c	(working copy)
@@ -147,7 +147,7 @@
 	/* 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 @@
 
 	/* 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 @@
 	 * 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 @@
 	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 @@
 		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;
 }
Index: sys/dev/ath/ath_hal/ar5416/ar5416.h
===================================================================
--- sys/dev/ath/ath_hal/ar5416/ar5416.h	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5416/ar5416.h	(working copy)
@@ -169,6 +169,7 @@
 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	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);
Index: sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c
===================================================================
--- sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c	(working copy)
@@ -29,6 +29,15 @@
 #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
  * driver calls ar5416SetStaBeaconTimers instead.
Index: sys/dev/ath/ath_hal/ar5416/ar5416_misc.c
===================================================================
--- sys/dev/ath/ath_hal/ar5416/ar5416_misc.c	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5416/ar5416_misc.c	(working copy)
@@ -93,6 +93,41 @@
 }
 
 /*
+ * 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.
  */
 void
Index: sys/dev/ath/ath_hal/ah_internal.h
===================================================================
--- sys/dev/ath/ath_hal/ah_internal.h	(revision 225143)
+++ sys/dev/ath/ath_hal/ah_internal.h	(working copy)
@@ -208,7 +208,8 @@
 			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;
Index: sys/dev/ath/ath_hal/ah.c
===================================================================
--- sys/dev/ath/ath_hal/ah.c	(revision 225143)
+++ sys/dev/ath/ath_hal/ah.c	(working copy)
@@ -657,6 +657,8 @@
 		}
 	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 @@
     }
     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);
+}
Index: sys/dev/ath/ath_hal/ar5210/ar5210_attach.c
===================================================================
--- sys/dev/ath/ath_hal/ar5210/ar5210_attach.c	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5210/ar5210_attach.c	(working copy)
@@ -148,6 +148,7 @@
 	.ah_beaconInit			= ar5210BeaconInit,
 	.ah_setStationBeaconTimers	= ar5210SetStaBeaconTimers,
 	.ah_resetStationBeaconTimers	= ar5210ResetStaBeaconTimers,
+	.ah_getNextTBTT			= ar5210GetNextTBTT,
 
 	/* Interrupt Functions */
 	.ah_isInterruptPending		= ar5210IsInterruptPending,
Index: sys/dev/ath/ath_hal/ar5210/ar5210.h
===================================================================
--- sys/dev/ath/ath_hal/ar5210/ar5210.h	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5210/ar5210.h	(working copy)
@@ -268,6 +268,7 @@
 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 *);
Index: sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c
===================================================================
--- sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c	(working copy)
@@ -27,6 +27,17 @@
 #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.
  */
 void
Index: sys/dev/ath/ath_hal/ar5211/ar5211_attach.c
===================================================================
--- sys/dev/ath/ath_hal/ar5211/ar5211_attach.c	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5211/ar5211_attach.c	(working copy)
@@ -148,6 +148,7 @@
 	.ah_beaconInit			= ar5211BeaconInit,
 	.ah_setStationBeaconTimers	= ar5211SetStaBeaconTimers,
 	.ah_resetStationBeaconTimers	= ar5211ResetStaBeaconTimers,
+	.ah_getNextTBTT			= ar5211GetNextTBTT,
 
 	/* Interrupt Functions */
 	.ah_isInterruptPending		= ar5211IsInterruptPending,
Index: sys/dev/ath/ath_hal/ar5211/ar5211.h
===================================================================
--- sys/dev/ath/ath_hal/ar5211/ar5211.h	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5211/ar5211.h	(working copy)
@@ -296,6 +296,7 @@
 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 *);
Index: sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c
===================================================================
--- sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c	(working copy)
@@ -30,6 +30,17 @@
  */
 
 /*
+ * 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.
  */
 void
Index: sys/dev/ath/ath_hal/ar5212/ar5212_attach.c
===================================================================
--- sys/dev/ath/ath_hal/ar5212/ar5212_attach.c	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5212/ar5212_attach.c	(working copy)
@@ -151,6 +151,7 @@
 	.ah_beaconInit			= ar5212BeaconInit,
 	.ah_setStationBeaconTimers	= ar5212SetStaBeaconTimers,
 	.ah_resetStationBeaconTimers	= ar5212ResetStaBeaconTimers,
+	.ah_getNextTBTT			= ar5212GetNextTBTT,
 
 	/* Interrupt Functions */
 	.ah_isInterruptPending		= ar5212IsInterruptPending,
Index: sys/dev/ath/ath_hal/ar5212/ar5212.h
===================================================================
--- sys/dev/ath/ath_hal/ar5212/ar5212.h	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5212/ar5212.h	(working copy)
@@ -430,6 +430,7 @@
 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 *);
Index: sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c
===================================================================
--- sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c	(revision 225143)
+++ sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c	(working copy)
@@ -26,6 +26,17 @@
 #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
  * driver calls ar5212SetStaBeaconTimers instead.
Index: sys/dev/ath/ath_hal/ah.h
===================================================================
--- sys/dev/ath/ath_hal/ah.h	(revision 225143)
+++ sys/dev/ath/ath_hal/ah.h	(working copy)
@@ -148,6 +148,7 @@
 	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 @@
 	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 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_ */
Index: sys/dev/ath/if_ath.c
===================================================================
--- sys/dev/ath/if_ath.c	(revision 225145)
+++ sys/dev/ath/if_ath.c	(working copy)
@@ -214,24 +214,6 @@
 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 @@
 	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,14 +3277,49 @@
  * 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 @@
 		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 @@
 			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 @@
 }
 
 #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 @@
 	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 @@
 	/* 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 @@
 	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 @@
 		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 @@
 		&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

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAJ-Vmok9n3Gh-Uiuaqh8Q6XOgOkeg_sKBKh1MqVXMQTkNTm42A>