ath9k: always issue a full hw reset after waking up from full-sleep mode
authorFelix Fietkau <nbd@openwrt.org>
Wed, 16 Nov 2011 12:08:40 +0000 (13:08 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 7 Dec 2011 20:14:03 +0000 (15:14 -0500)
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>
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/xmit.c

index fd59c1f25c43a7ea89907a3d2d5fc3f5bc275184..3733828e72bc7267e5a09d0a690636b210c5a3db 100644 (file)
@@ -118,7 +118,7 @@ void ath9k_ps_restore(struct ath_softc *sc)
        if (--sc->ps_usecount != 0)
                goto unlock;
 
-       if (sc->ps_idle)
+       if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK))
                mode = ATH9K_PM_FULL_SLEEP;
        else if (sc->ps_enabled &&
                 !(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;
        }
 
-       if (fastcc && !ath9k_hw_check_alive(ah))
+       if (fastcc && (ah->chip_fullsleep ||
+           !ath9k_hw_check_alive(ah)))
                fastcc = false;
 
        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)) {
                /*
                 * We are using PS-Poll and mac80211 can request TX while in
index 80639e3e4ac9ee94a2e2f105e77c3852b15c2c71..9e65c3198ca7b9272f323fc21cb1d50fa203ac74 100644 (file)
@@ -1954,7 +1954,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                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;
                ath_dbg(common, ATH_DBG_PS,
                        "Going back to sleep after having received TX status (0x%lx)\n",