If we are in NETWORK_SLEEP state, calling of 'ath9k_hw_setrxabort' in
'ath9k_config' will fail with the following error:
ath9k: timeout (100000 us) on reg 0x806c: 0xdeadbeef & 0x01f00000 != 0x00000000
ath9k: RX failed to go idle in 10 ms RXSM=0xdeadbeef
Fix it by waking up the chip, and set 'ps_restore_mode' directly instead
of calling the 'ath9k_hw_setpower' routine..
The problem is reported by Luis:
http://article.gmane.org/gmane.linux.kernel.wireless.general/34363
Changes-licensed-under: ISC
Signed-off-by: Gabor Juhos <[email protected]>
---
drivers/net/wireless/ath/ath9k/hw.c | 4 +---
drivers/net/wireless/ath/ath9k/main.c | 6 ++++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 605803a..53dfc6d 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2783,10 +2783,8 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
if (++sc->ps_usecount != 1)
goto unlock;
- if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
- sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
+ if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
- }
unlock:
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 3436295..826e9c8 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2281,6 +2281,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
if (changed & IEEE80211_CONF_CHANGE_PS) {
+ ath9k_ps_wakeup(sc);
if (conf->flags & IEEE80211_CONF_PS) {
if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) {
@@ -2291,9 +2292,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
ath9k_hw_setrxabort(sc->sc_ah, 1);
}
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
+ sc->sc_ah->restore_mode = ATH9K_PM_NETWORK_SLEEP;
} else {
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
+ sc->sc_ah->restore_mode = ATH9K_PM_AWAKE;
if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) {
ath9k_hw_setrxabort(sc->sc_ah, 0);
@@ -2308,6 +2309,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
}
}
+ ath9k_ps_restore(sc);
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
--
1.5.3.2
Vasanthakumar Thiagarajan ?rta:
> On Thu, Jul 23, 2009 at 02:04:11PM +0530, Gabor Juhos wrote:
>> If we are in NETWORK_SLEEP state, calling of 'ath9k_hw_setrxabort' in
>> 'ath9k_config' will fail with the following error:
>>
>> ath9k: timeout (100000 us) on reg 0x806c: 0xdeadbeef & 0x01f00000 != 0x00000000
>> ath9k: RX failed to go idle in 10 ms RXSM=0xdeadbeef
>>
>> Fix it by waking up the chip, and set 'ps_restore_mode' directly instead
>> of calling the 'ath9k_hw_setpower' routine..
>>
>> The problem is reported by Luis:
>> http://article.gmane.org/gmane.linux.kernel.wireless.general/34363
>>
>> Changes-licensed-under: ISC
>> Signed-off-by: Gabor Juhos <[email protected]>
>> ---
>> if (changed & IEEE80211_CONF_CHANGE_PS) {
>> + ath9k_ps_wakeup(sc);
>
> This seems to be a workaround. chip should not be sleeping when
> mac80211 thinks it is awake.
Hm, first I thought this is a bug in ath9k:
ath9k: AWAKE -> NETWORK SLEEP
ath9k: timeout (100000 us) on reg 0x806c: 0xdeadbeef & 0x01f00000 != 0x00000000
ath9k: RX failed to go idle in 10 ms RXSM=0xdeadbeef
ath9k: NETWORK SLEEP -> NETWORK SLEEP
You are righ probably, this can happen when mac80211 tells us to enter PS mode,
even if we are in it currently. Although I have no idea yet how this may happen.
Gabor
On Thu, Jul 23, 2009 at 02:04:11PM +0530, Gabor Juhos wrote:
> If we are in NETWORK_SLEEP state, calling of 'ath9k_hw_setrxabort' in
> 'ath9k_config' will fail with the following error:
>
> ath9k: timeout (100000 us) on reg 0x806c: 0xdeadbeef & 0x01f00000 != 0x00000000
> ath9k: RX failed to go idle in 10 ms RXSM=0xdeadbeef
>
> Fix it by waking up the chip, and set 'ps_restore_mode' directly instead
> of calling the 'ath9k_hw_setpower' routine..
>
> The problem is reported by Luis:
> http://article.gmane.org/gmane.linux.kernel.wireless.general/34363
>
> Changes-licensed-under: ISC
> Signed-off-by: Gabor Juhos <[email protected]>
> ---
> if (changed & IEEE80211_CONF_CHANGE_PS) {
> + ath9k_ps_wakeup(sc);
This seems to be a workaround. chip should not be sleeping when
mac80211 thinks it is awake.
Vasanth
We are using setpower routines regardless of the current power mode.
Don't bother the hardware, if it is not necessary.
Changes-licensed-under: ISC
Signed-off-by: Gabor Juhos <[email protected]>
---
drivers/net/wireless/ath/ath9k/hw.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 53dfc6d..d958a0e 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -475,6 +475,8 @@ static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
ah->gbeacon_rate = 0;
+ ah->power_mode = ATH9K_PM_UNDEFINED;
+
return ah;
}
@@ -2739,6 +2741,9 @@ static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
"UNDEFINED"
};
+ if (ah->power_mode == mode)
+ return status;
+
DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n",
modes[ah->power_mode], modes[mode]);
@@ -2783,8 +2788,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc)
if (++sc->ps_usecount != 1)
goto unlock;
- if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
- ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
+ ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
unlock:
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
--
1.5.3.2