ath9k: Update Beacon timers based on timestamp from the AP
authorJouni Malinen <jouni.malinen@atheros.com>
Wed, 20 May 2009 18:59:08 +0000 (21:59 +0300)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 22 May 2009 18:06:01 +0000 (14:06 -0400)
Some APs seem to drift away from the expected TBTT (timestamp %
beacon_int_in_usec differs quite a bit from zero) which can result in
us waking up way too early to receive a Beacon frame. In order to work
around this, re-configure the Beacon timers after having received a
Beacon frame from the AP (i.e., when we know the offset between the
expected TBTT and the actual time the AP is sending out the Beacon
frame).

Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c

index 0d4ac43..796a3ad 100644 (file)
@@ -518,6 +518,7 @@ struct ath_rfkill {
 #define SC_OP_WAIT_FOR_CAB      BIT(16)
 #define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17)
 #define SC_OP_WAIT_FOR_TX_ACK   BIT(18)
+#define SC_OP_BEACON_SYNC       BIT(19)
 
 struct ath_bus_ops {
        void            (*read_cachesize)(struct ath_softc *sc, int *csz);
index 5759c94..61da08a 100644 (file)
@@ -487,7 +487,7 @@ static void ath9k_tasklet(unsigned long data)
                 * the next Beacon.
                 */
                DPRINTF(sc, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n");
-               sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
+               sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC;
        }
 
        /* re-enable hardware interrupt */
@@ -914,6 +914,13 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
                if (avp->av_opmode == NL80211_IFTYPE_STATION) {
                        sc->curaid = bss_conf->aid;
                        ath9k_hw_write_associd(sc);
+
+                       /*
+                        * Request a re-configuration of Beacon related timers
+                        * on the receipt of the first Beacon frame (i.e.,
+                        * after time sync with the AP).
+                        */
+                       sc->sc_flags |= SC_OP_BEACON_SYNC;
                }
 
                /* Configure the beacon */
index 5e046b5..5014a19 100644 (file)
@@ -521,6 +521,13 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
        if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0)
                return; /* not from our current AP */
 
+       if (sc->sc_flags & SC_OP_BEACON_SYNC) {
+               sc->sc_flags &= ~SC_OP_BEACON_SYNC;
+               DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on "
+                       "timestamp from the AP\n");
+               ath_beacon_config(sc, NULL);
+       }
+
        if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) {
                /* We are not in PS mode anymore; remain awake */
                DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain "