2013-11-18 19:14:55

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 1/2] ath9k_hw: fix TSF save/restore around chip reset

A cold reset can be triggered because of DMA stop issues, and this leads
to TSF being cleared on all chipsets. To properly deal with this, always
save the TSF.
Additionally, account for the time it takes to do the actual chip reset,
which can be quite significant. On AR9344 it takes around 4.5 ms.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/hw.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 54b0415..4046da5 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -17,6 +17,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/time.h>
#include <asm/unaligned.h>

#include "hw.h"
@@ -1856,10 +1857,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
struct ath9k_hw_cal_data *caldata, bool fastcc)
{
struct ath_common *common = ath9k_hw_common(ah);
+ struct timespec ts;
u32 saveLedState;
u32 saveDefAntenna;
u32 macStaId1;
u64 tsf = 0;
+ s64 usec = 0;
int r;
bool start_mci_reset = false;
bool save_fullsleep = ah->chip_fullsleep;
@@ -1902,10 +1905,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,

macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;

- /* For chips on which RTC reset is done, save TSF before it gets cleared */
- if (AR_SREV_9100(ah) ||
- (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)))
- tsf = ath9k_hw_gettsf64(ah);
+ /* Save TSF before chip reset, a cold reset clears it */
+ tsf = ath9k_hw_gettsf64(ah);
+ getrawmonotonic(&ts);
+ usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000;

saveLedState = REG_READ(ah, AR_CFG_LED) &
(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
@@ -1938,8 +1941,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
}

/* Restore TSF */
- if (tsf)
- ath9k_hw_settsf64(ah, tsf);
+ getrawmonotonic(&ts);
+ usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000 - usec;
+ ath9k_hw_settsf64(ah, tsf + usec);

if (AR_SREV_9280_20_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
--
1.8.3.4 (Apple Git-47)



2013-11-18 22:55:58

by Sujith Manoharan

[permalink] [raw]
Subject: Re: [PATCH 1/2] ath9k_hw: fix TSF save/restore around chip reset

Felix Fietkau wrote:
> A cold reset can be triggered because of DMA stop issues, and this leads
> to TSF being cleared on all chipsets. To properly deal with this, always
> save the TSF.

I think this needs to be done only when we are in operational state.
There is no need to do this before the station interface is associated
or the AP interface is up.

Sujith

2013-11-18 23:34:06

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH 1/2] ath9k_hw: fix TSF save/restore around chip reset

On 2013-11-18 23:51, Sujith Manoharan wrote:
> Felix Fietkau wrote:
>> A cold reset can be triggered because of DMA stop issues, and this leads
>> to TSF being cleared on all chipsets. To properly deal with this, always
>> save the TSF.
>
> I think this needs to be done only when we are in operational state.
> There is no need to do this before the station interface is associated
> or the AP interface is up.
Technically yes, but in practice it doesn't really matter, so I'd prefer
to keep the code simple.
For scanning we don't really hit this codepath much anyway: The first
reset skips it because of the transition out of full-sleep, subsequent
resets tend to use fast channel changes most of the time, which also
doesn't do the TSF save/restore.

- Felix


2013-11-18 19:14:57

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 2/2] ath9k_hw: allow fast channel change when only CHANNEL_HT changes

The CHANNEL_HT flag is insignificant for fast channel change conditions,
since it does not affect any important part of the hardware reset /
channel setup.
Scanning usually runs with HT disabled, so this change will slightly
improve scan time on many chipsets.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/hw.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 4046da5..94652e5 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1503,8 +1503,9 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
int r;

if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) {
- band_switch = IS_CHAN_5GHZ(ah->curchan) != IS_CHAN_5GHZ(chan);
- mode_diff = (chan->channelFlags != ah->curchan->channelFlags);
+ u32 flags_diff = chan->channelFlags ^ ah->curchan->channelFlags;
+ band_switch = !!(flags_diff & CHANNEL_5GHZ);
+ mode_diff = !!(flags_diff & ~CHANNEL_HT);
}

for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
@@ -1816,7 +1817,7 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
* If cross-band fcc is not supoprted, bail out if channelFlags differ.
*/
if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) &&
- chan->channelFlags != ah->curchan->channelFlags)
+ ((chan->channelFlags ^ ah->curchan->channelFlags) & ~CHANNEL_HT))
goto fail;

if (!ath9k_hw_check_alive(ah))
--
1.8.3.4 (Apple Git-47)