Commit 8d7e09dd authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville

ath9k: save tsf in channel context

Save TSF in channel context for multiple operating channels.
Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarRajkumar Manoharan <rmanohar@qti.qualcomm.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 26f16c24
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/time.h>
#include "common.h" #include "common.h"
#include "debug.h" #include "debug.h"
...@@ -328,6 +329,8 @@ struct ath_chanctx { ...@@ -328,6 +329,8 @@ struct ath_chanctx {
struct list_head acq[IEEE80211_NUM_ACS]; struct list_head acq[IEEE80211_NUM_ACS];
struct ath9k_hw_cal_data caldata; struct ath9k_hw_cal_data caldata;
struct timespec tsf_ts;
u64 tsf_val;
u16 txpower; u16 txpower;
bool offchannel; bool offchannel;
......
...@@ -227,6 +227,11 @@ void ath_chanctx_work(struct work_struct *work) ...@@ -227,6 +227,11 @@ void ath_chanctx_work(struct work_struct *work)
send_ps = true; send_ps = true;
spin_lock_bh(&sc->chan_lock); 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 = sc->next_chan;
sc->cur_chan->stopped = false; sc->cur_chan->stopped = false;
......
...@@ -1730,6 +1730,23 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) ...@@ -1730,6 +1730,23 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
return -EINVAL; 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, int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
struct ath9k_hw_cal_data *caldata, bool fastcc) struct ath9k_hw_cal_data *caldata, bool fastcc)
{ {
...@@ -1739,7 +1756,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ...@@ -1739,7 +1756,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
u32 saveDefAntenna; u32 saveDefAntenna;
u32 macStaId1; u32 macStaId1;
u64 tsf = 0; u64 tsf = 0;
s64 usec = 0;
int r; int r;
bool start_mci_reset = false; bool start_mci_reset = false;
bool save_fullsleep = ah->chip_fullsleep; bool save_fullsleep = ah->chip_fullsleep;
...@@ -1785,7 +1801,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ...@@ -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 */ /* Save TSF before chip reset, a cold reset clears it */
tsf = ath9k_hw_gettsf64(ah); tsf = ath9k_hw_gettsf64(ah);
getrawmonotonic(&ts); getrawmonotonic(&ts);
usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000;
saveLedState = REG_READ(ah, AR_CFG_LED) & saveLedState = REG_READ(ah, AR_CFG_LED) &
(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | (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, ...@@ -1818,9 +1833,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
} }
/* Restore TSF */ /* Restore TSF */
getrawmonotonic(&ts); ath9k_hw_settsf64(ah, tsf + ath9k_hw_get_tsf_offset(&ts, NULL));
usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000 - usec;
ath9k_hw_settsf64(ah, tsf + usec);
if (AR_SREV_9280_20_OR_LATER(ah)) if (AR_SREV_9280_20_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
......
...@@ -1000,6 +1000,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah); ...@@ -1000,6 +1000,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah);
u64 ath9k_hw_gettsf64(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_settsf64(struct ath_hw *ah, u64 tsf64);
void ath9k_hw_reset_tsf(struct ath_hw *ah); 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_set_tsfadjust(struct ath_hw *ah, bool set);
void ath9k_hw_init_global_settings(struct ath_hw *ah); void ath9k_hw_init_global_settings(struct ath_hw *ah);
u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah);
......
...@@ -240,6 +240,16 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ...@@ -240,6 +240,16 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
ath9k_hw_enable_interrupts(ah); ath9k_hw_enable_interrupts(ah);
if (!sc->cur_chan->offchannel && start) { 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)) if (!test_bit(ATH_OP_BEACONS, &common->op_flags))
goto work; goto work;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment