Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 Aug 2011 20:01:27 +0800
From:      Kang Yin Su <cantona@cantona.net>
To:        freebsd-wireless@freebsd.org
Subject:   [PATCH] TDMA beacon from slave station
Message-ID:  <CAHjFwoDRFMGRJnCCd9PQcksZ-pEg=SUAL1q-4scOnXjmTQArYQ@mail.gmail.com>

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

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

This patch modify the following:

1. Relocate 'ath_hal_*' functions from if_ath.c to appropriate HAL
layer and moved those common functions to ah.c
2. The next TBTT register mistakenly used in AR6416 that cause
intermittent beacons transmit form a TDMA slave station.
  - Use AR_NEXT_TBTT instead of AR_TIMER0 for AR5416.
3. Do not adjust the beacon timers when 'tudelta' value is multiple of
tdmabintval value. It causes the timers to stop and beacon stuck.

Thanks,
Yin

[-- Attachment #2 --]
Index: if_athvar.h
===================================================================
--- if_athvar.h	(revision 225242)
+++ if_athvar.h	(working copy)
@@ -482,6 +482,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) \
Index: ath_hal/ar5416/ar5416_attach.c
===================================================================
--- ath_hal/ar5416/ar5416_attach.c	(revision 225242)
+++ 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;
Index: ath_hal/ar5416/ar5416_reset.c
===================================================================
--- ath_hal/ar5416/ar5416_reset.c	(revision 225242)
+++ 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",
@@ -503,7 +503,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: ath_hal/ar5416/ar5416.h
===================================================================
--- ath_hal/ar5416/ar5416.h	(revision 225242)
+++ 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: ath_hal/ar5416/ar5416_beacon.c
===================================================================
--- ath_hal/ar5416/ar5416_beacon.c	(revision 225242)
+++ 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: ath_hal/ar5416/ar5416_misc.c
===================================================================
--- ath_hal/ar5416/ar5416_misc.c	(revision 225242)
+++ 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: ath_hal/ah.c
===================================================================
--- ath_hal/ah.c	(revision 225242)
+++ ath_hal/ah.c	(working copy)
@@ -1222,3 +1222,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: ath_hal/ar5210/ar5210_attach.c
===================================================================
--- ath_hal/ar5210/ar5210_attach.c	(revision 225242)
+++ 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: ath_hal/ar5210/ar5210.h
===================================================================
--- ath_hal/ar5210/ar5210.h	(revision 225242)
+++ 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: ath_hal/ar5210/ar5210_beacon.c
===================================================================
--- ath_hal/ar5210/ar5210_beacon.c	(revision 225242)
+++ 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: ath_hal/ar5211/ar5211_attach.c
===================================================================
--- ath_hal/ar5211/ar5211_attach.c	(revision 225242)
+++ 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: ath_hal/ar5211/ar5211.h
===================================================================
--- ath_hal/ar5211/ar5211.h	(revision 225242)
+++ 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: ath_hal/ar5211/ar5211_beacon.c
===================================================================
--- ath_hal/ar5211/ar5211_beacon.c	(revision 225242)
+++ 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: ath_hal/ar5212/ar5212_attach.c
===================================================================
--- ath_hal/ar5212/ar5212_attach.c	(revision 225242)
+++ 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: ath_hal/ar5212/ar5212.h
===================================================================
--- ath_hal/ar5212/ar5212.h	(revision 225242)
+++ 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: ath_hal/ar5212/ar5212_beacon.c
===================================================================
--- ath_hal/ar5212/ar5212_beacon.c	(revision 225242)
+++ 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: ath_hal/ah.h
===================================================================
--- ath_hal/ah.h	(revision 225242)
+++ ath_hal/ah.h	(working copy)
@@ -996,6 +996,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 +1139,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: if_ath.c
===================================================================
--- if_ath.c	(revision 225242)
+++ 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
@@ -5460,20 +5442,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 +5597,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;
@@ -5677,15 +5645,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 +5673,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 +5692,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
@@ -5736,7 +5703,8 @@
 	 * cause the timers to stop and generally cause instability.
 	 * This basically filters out jumps due to missed beacons.
 	 */
-	if (tudelta != 0 && (tudelta > 0 || -tudelta < sc->sc_tdmabintval)) {
+	if (tudelta != 0 && (tudelta > 0 || -tudelta < sc->sc_tdmabintval) &&
+		(tudelta % sc->sc_tdmabintval != 0)) {
 		ath_tdma_settimers(sc, nextslottu, sc->sc_tdmabintval);
 		sc->sc_stats.ast_tdma_timers++;
 	}

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAHjFwoDRFMGRJnCCd9PQcksZ-pEg=SUAL1q-4scOnXjmTQArYQ>