ath9k: save tsf in channel context
authorFelix Fietkau <nbd@openwrt.org>
Wed, 11 Jun 2014 10:48:01 +0000 (16:18 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 19 Jun 2014 19:49:18 +0000 (15:49 -0400)
Save TSF in channel context for multiple operating channels.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/channel.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/main.c

index ffacbf6e9f52e370b52ce41478ec61fadfa678a9..4df412b716802a8f3929af057fedc43b4897131c 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/leds.h>
 #include <linux/completion.h>
+#include <linux/time.h>
 
 #include "common.h"
 #include "debug.h"
@@ -328,6 +329,8 @@ struct ath_chanctx {
        struct list_head acq[IEEE80211_NUM_ACS];
 
        struct ath9k_hw_cal_data caldata;
+       struct timespec tsf_ts;
+       u64 tsf_val;
 
        u16 txpower;
        bool offchannel;
index e3127b52e1eeb8b32fbe2a9f55774762ea050561..4a7691eecdb4636b3a0b939a34201abef3ecc135 100644 (file)
@@ -227,6 +227,11 @@ void ath_chanctx_work(struct work_struct *work)
 
                send_ps = true;
                spin_lock_bh(&sc->chan_lock);
+
+               if (sc->cur_chan != &sc->offchannel.chan) {
+                       getrawmonotonic(&sc->cur_chan->tsf_ts);
+                       sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah);
+               }
        }
        sc->cur_chan = sc->next_chan;
        sc->cur_chan->stopped = false;
index 2a8ed8375ec0584771f4f7dcc833d17131ec34b2..ace4fe2740d4d2023b418f439684d3835b984e97 100644 (file)
@@ -1730,6 +1730,23 @@ fail:
        return -EINVAL;
 }
 
+u32 ath9k_hw_get_tsf_offset(struct timespec *last, struct timespec *cur)
+{
+       struct timespec ts;
+       s64 usec;
+
+       if (!cur) {
+               getrawmonotonic(&ts);
+               cur = &ts;
+       }
+
+       usec = cur->tv_sec * 1000000ULL + cur->tv_nsec / 1000;
+       usec -= last->tv_sec * 1000000ULL + last->tv_nsec / 1000;
+
+       return (u32) usec;
+}
+EXPORT_SYMBOL(ath9k_hw_get_tsf_offset);
+
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                   struct ath9k_hw_cal_data *caldata, bool fastcc)
 {
@@ -1739,7 +1756,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        u32 saveDefAntenna;
        u32 macStaId1;
        u64 tsf = 0;
-       s64 usec = 0;
        int r;
        bool start_mci_reset = false;
        bool save_fullsleep = ah->chip_fullsleep;
@@ -1785,7 +1801,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        /* Save TSF before chip reset, a cold reset clears it */
        tsf = ath9k_hw_gettsf64(ah);
        getrawmonotonic(&ts);
-       usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000;
 
        saveLedState = REG_READ(ah, AR_CFG_LED) &
                (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
@@ -1818,9 +1833,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        }
 
        /* Restore TSF */
-       getrawmonotonic(&ts);
-       usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000 - usec;
-       ath9k_hw_settsf64(ah, tsf + usec);
+       ath9k_hw_settsf64(ah, tsf + ath9k_hw_get_tsf_offset(&ts, NULL));
 
        if (AR_SREV_9280_20_OR_LATER(ah))
                REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
index 0acd4b5a48929f4443fde73706f6ee6bb8ce7a0b..51b4ebe04c04faaf612c744b2bbad93001c46622 100644 (file)
@@ -1000,6 +1000,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah);
 u64 ath9k_hw_gettsf64(struct ath_hw *ah);
 void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
 void ath9k_hw_reset_tsf(struct ath_hw *ah);
+u32 ath9k_hw_get_tsf_offset(struct timespec *last, struct timespec *cur);
 void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set);
 void ath9k_hw_init_global_settings(struct ath_hw *ah);
 u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah);
index 85db24be8eec04c2c388141796049ce9667bc708..6abdf99ffae41539d82a4a9e790fdd5cd3cef631 100644 (file)
@@ -240,6 +240,16 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
        ath9k_hw_enable_interrupts(ah);
 
        if (!sc->cur_chan->offchannel && start) {
+               /* restore per chanctx TSF timer */
+               if (sc->cur_chan->tsf_val) {
+                       u32 offset;
+
+                       offset = ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts,
+                                                        NULL);
+                       ath9k_hw_settsf64(ah, sc->cur_chan->tsf_val + offset);
+               }
+
+
                if (!test_bit(ATH_OP_BEACONS, &common->op_flags))
                        goto work;