aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBruno Randolf <bruno@thinktube.com>2008-01-19 04:17:59 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:10:51 -0500
commit9804b98d57f9b3b02a8906b0b45f461ce0c08428 (patch)
tree6221cc08c4e9a71f45296fc9862f6e137d0712be /drivers
parente535c1ac7e431f85e9c8ead6dbc977a1e1906736 (diff)
ath5k: better beacon timer calculation
update ath5k_beacon_update_timers() for better beacon timer calculation in a variety of situations. most important is the possibility to call it with the timestamp of a received beacon, when we detected that a HW merge has happened and we need to reconfigure the beacon timers based on that. we call this from the mac80211 callback reset_tsf now instead of beacon_update, and there will be more use of it in the next patch. drivers/net/wireless/ath5k/base.c: Changes-licensed-under: 3-Clause-BSD Signed-off-by: Bruno Randolf <bruno@thinktube.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath5k/base.c109
1 files changed, 92 insertions, 17 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index de590163a07e..c49061c51688 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -290,6 +290,7 @@ static int ath5k_beacon_setup(struct ath5k_softc *sc,
290 struct ieee80211_tx_control *ctl); 290 struct ieee80211_tx_control *ctl);
291static void ath5k_beacon_send(struct ath5k_softc *sc); 291static void ath5k_beacon_send(struct ath5k_softc *sc);
292static void ath5k_beacon_config(struct ath5k_softc *sc); 292static void ath5k_beacon_config(struct ath5k_softc *sc);
293static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
293 294
294static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) 295static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
295{ 296{
@@ -1984,34 +1985,102 @@ ath5k_beacon_send(struct ath5k_softc *sc)
1984} 1985}
1985 1986
1986 1987
1988/**
1989 * ath5k_beacon_update_timers - update beacon timers
1990 *
1991 * @sc: struct ath5k_softc pointer we are operating on
1992 * @bc_tsf: the timestamp of the beacon. 0 to reset the TSF. -1 to perform a
1993 * beacon timer update based on the current HW TSF.
1994 *
1995 * Calculate the next target beacon transmit time (TBTT) based on the timestamp
1996 * of a received beacon or the current local hardware TSF and write it to the
1997 * beacon timer registers.
1998 *
1999 * This is called in a variety of situations, e.g. when a beacon is received,
2000 * when a HW merge has been detected, but also when an new IBSS is created or
2001 * when we otherwise know we have to update the timers, but we keep it in this
2002 * function to have it all together in one place.
2003 */
1987static void 2004static void
1988ath5k_beacon_update_timers(struct ath5k_softc *sc) 2005ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
1989{ 2006{
1990 struct ath5k_hw *ah = sc->ah; 2007 struct ath5k_hw *ah = sc->ah;
1991 u32 uninitialized_var(nexttbtt), intval, tsftu; 2008 u32 nexttbtt, intval, hw_tu, bc_tu;
1992 u64 tsf; 2009 u64 hw_tsf;
1993 2010
1994 intval = sc->bintval & AR5K_BEACON_PERIOD; 2011 intval = sc->bintval & AR5K_BEACON_PERIOD;
1995 if (WARN_ON(!intval)) 2012 if (WARN_ON(!intval))
1996 return; 2013 return;
1997 2014
1998 /* current TSF converted to TU */ 2015 /* beacon TSF converted to TU */
1999 tsf = ath5k_hw_get_tsf64(ah); 2016 bc_tu = TSF_TO_TU(bc_tsf);
2000 tsftu = TSF_TO_TU(tsf);
2001 2017
2002 /* 2018 /* current TSF converted to TU */
2003 * Pull nexttbtt forward to reflect the current 2019 hw_tsf = ath5k_hw_get_tsf64(ah);
2004 * TSF. Add one intval otherwise the timespan 2020 hw_tu = TSF_TO_TU(hw_tsf);
2005 * can be too short for ibss merges.
2006 */
2007 nexttbtt = tsftu + 2 * intval;
2008 2021
2009 ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, 2022#define FUDGE 3
2010 "hw tsftu %u nexttbtt %u intval %u\n", tsftu, nexttbtt, intval); 2023 /* we use FUDGE to make sure the next TBTT is ahead of the current TU */
2024 if (bc_tsf == -1) {
2025 /*
2026 * no beacons received, called internally.
2027 * just need to refresh timers based on HW TSF.
2028 */
2029 nexttbtt = roundup(hw_tu + FUDGE, intval);
2030 } else if (bc_tsf == 0) {
2031 /*
2032 * no beacon received, probably called by ath5k_reset_tsf().
2033 * reset TSF to start with 0.
2034 */
2035 nexttbtt = intval;
2036 intval |= AR5K_BEACON_RESET_TSF;
2037 } else if (bc_tsf > hw_tsf) {
2038 /*
2039 * beacon received, SW merge happend but HW TSF not yet updated.
2040 * not possible to reconfigure timers yet, but next time we
2041 * receive a beacon with the same BSSID, the hardware will
2042 * automatically update the TSF and then we need to reconfigure
2043 * the timers.
2044 */
2045 ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
2046 "need to wait for HW TSF sync\n");
2047 return;
2048 } else {
2049 /*
2050 * most important case for beacon synchronization between STA.
2051 *
2052 * beacon received and HW TSF has been already updated by HW.
2053 * update next TBTT based on the TSF of the beacon, but make
2054 * sure it is ahead of our local TSF timer.
2055 */
2056 nexttbtt = bc_tu + roundup(hw_tu + FUDGE - bc_tu, intval);
2057 }
2058#undef FUDGE
2011 2059
2012 intval |= AR5K_BEACON_ENA; 2060 intval |= AR5K_BEACON_ENA;
2013
2014 ath5k_hw_init_beacon(ah, nexttbtt, intval); 2061 ath5k_hw_init_beacon(ah, nexttbtt, intval);
2062
2063 /*
2064 * debugging output last in order to preserve the time critical aspect
2065 * of this function
2066 */
2067 if (bc_tsf == -1)
2068 ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
2069 "reconfigured timers based on HW TSF\n");
2070 else if (bc_tsf == 0)
2071 ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
2072 "reset HW TSF and timers\n");
2073 else
2074 ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
2075 "updated timers based on beacon TSF\n");
2076
2077 ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
2078 "bc_tsf %llx hw_tsf %llx bc_tu %u hw_tu %u nexttbtt %u\n",
2079 bc_tsf, hw_tsf, bc_tu, hw_tu, nexttbtt);
2080 ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "intval %u %s %s\n",
2081 intval & AR5K_BEACON_PERIOD,
2082 intval & AR5K_BEACON_ENA ? "AR5K_BEACON_ENA" : "",
2083 intval & AR5K_BEACON_RESET_TSF ? "AR5K_BEACON_RESET_TSF" : "");
2015} 2084}
2016 2085
2017 2086
@@ -2045,7 +2114,6 @@ ath5k_beacon_config(struct ath5k_softc *sc)
2045 * only once here. 2114 * only once here.
2046 */ 2115 */
2047 ath5k_beaconq_config(sc); 2116 ath5k_beaconq_config(sc);
2048 ath5k_beacon_update_timers(sc);
2049 2117
2050 if (!ath5k_hw_hasveol(ah)) 2118 if (!ath5k_hw_hasveol(ah))
2051 sc->imask |= AR5K_INT_SWBA; 2119 sc->imask |= AR5K_INT_SWBA;
@@ -2795,7 +2863,14 @@ ath5k_reset_tsf(struct ieee80211_hw *hw)
2795{ 2863{
2796 struct ath5k_softc *sc = hw->priv; 2864 struct ath5k_softc *sc = hw->priv;
2797 2865
2798 ath5k_hw_reset_tsf(sc->ah); 2866 /*
2867 * in IBSS mode we need to update the beacon timers too.
2868 * this will also reset the TSF if we call it with 0
2869 */
2870 if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
2871 ath5k_beacon_update_timers(sc, 0);
2872 else
2873 ath5k_hw_reset_tsf(sc->ah);
2799} 2874}
2800 2875
2801static int 2876static int