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

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: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 4e79fada
...@@ -118,7 +118,7 @@ void ath9k_ps_restore(struct ath_softc *sc) ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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",
......
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