ath9k: always issue a full hw reset after waking up from full-sleep mode
After waking up from full sleep, registers are accessible, but rx/tx typically fails. A fast channel change will not recover from this, so ensure that a full-sleep -> wake transition is always followed by a full reset. The reason why this hasn't created any serious problems yet is that it's hidden by the (wrong) behavior of enabling/disabling the radio when the wiphy idle state changes. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
4e79fada02
commit
c8e8868e3b
2 changed files with 11 additions and 3 deletions
|
@ -118,7 +118,7 @@ void ath9k_ps_restore(struct ath_softc *sc)
|
||||||
if (--sc->ps_usecount != 0)
|
if (--sc->ps_usecount != 0)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
if (sc->ps_idle)
|
if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK))
|
||||||
mode = ATH9K_PM_FULL_SLEEP;
|
mode = ATH9K_PM_FULL_SLEEP;
|
||||||
else if (sc->ps_enabled &&
|
else if (sc->ps_enabled &&
|
||||||
!(sc->ps_flags & (PS_WAIT_FOR_BEACON |
|
!(sc->ps_flags & (PS_WAIT_FOR_BEACON |
|
||||||
|
@ -332,7 +332,8 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
|
||||||
hchan = ah->curchan;
|
hchan = ah->curchan;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fastcc && !ath9k_hw_check_alive(ah))
|
if (fastcc && (ah->chip_fullsleep ||
|
||||||
|
!ath9k_hw_check_alive(ah)))
|
||||||
fastcc = false;
|
fastcc = false;
|
||||||
|
|
||||||
if (!ath_prepare_reset(sc, retry_tx, flush))
|
if (!ath_prepare_reset(sc, retry_tx, flush))
|
||||||
|
@ -1183,6 +1184,13 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cannot tx while the hardware is in full sleep, it first needs a full
|
||||||
|
* chip reset to recover from that
|
||||||
|
*/
|
||||||
|
if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) {
|
if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) {
|
||||||
/*
|
/*
|
||||||
* We are using PS-Poll and mac80211 can request TX while in
|
* We are using PS-Poll and mac80211 can request TX while in
|
||||||
|
|
|
@ -1954,7 +1954,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
||||||
skb_pull(skb, padsize);
|
skb_pull(skb, padsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
|
if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
|
||||||
sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
|
sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
|
||||||
ath_dbg(common, ATH_DBG_PS,
|
ath_dbg(common, ATH_DBG_PS,
|
||||||
"Going back to sleep after having received TX status (0x%lx)\n",
|
"Going back to sleep after having received TX status (0x%lx)\n",
|
||||||
|
|
Loading…
Reference in a new issue