This patch doesn't apply to the .37 stable tree. If someone wants it applied there, please email the backport to [email protected]
thanks, greg k-h > commit: 6a6733f256f18cbcf4875e13f59eedb593b755a8 > From: Luis R. Rodriguez <[email protected]> > Date: Tue, 26 Oct 2010 15:27:25 -0700 > Subject: [PATCH] ath9k: content DMA start / stop through the PCU lock > > This helps align resets / RX enable & disable / TX stop / start. > Locking around the PCU is important to ensure the hardware doesn't > get stale data when working with DMA'able data. > > This is part of a series of patches which fix stopping > TX DMA completley when requested on the driver. > For more details about this issue refer to this thread: > > http://marc.info/?l=linux-wireless&m=128629803703756&w=2 > > Tested-by: Ben Greear <[email protected]> > Cc: Kyungwan Nam <[email protected]> > Cc: [email protected] > Signed-off-by: Luis R. Rodriguez <[email protected]> > Signed-off-by: John W. Linville <[email protected]> > --- > drivers/net/wireless/ath/ath9k/main.c | 52 ++++++++++++++++---------------- > drivers/net/wireless/ath/ath9k/xmit.c | 2 - > 2 files changed, 26 insertions(+), 28 deletions(-) > > diff --git a/drivers/net/wireless/ath/ath9k/main.c > b/drivers/net/wireless/ath/ath9k/main.c > index 463ac12..d522112 100644 > --- a/drivers/net/wireless/ath/ath9k/main.c > +++ b/drivers/net/wireless/ath/ath9k/main.c > @@ -230,6 +230,8 @@ int ath_set_channel(struct ath_softc *sc, struct > ieee80211_hw *hw, > > ath9k_ps_wakeup(sc); > > + spin_lock_bh(&sc->sc_pcu_lock); > + > /* > * This is only performed if the channel settings have > * actually changed. > @@ -242,8 +244,6 @@ int ath_set_channel(struct ath_softc *sc, struct > ieee80211_hw *hw, > ath9k_hw_disable_interrupts(ah); > ath_drain_all_txq(sc, false); > > - spin_lock_bh(&sc->sc_pcu_lock); > - > stopped = ath_stoprecv(sc); > > /* XXX: do not flush receive queue here. We don't want > @@ -268,7 +268,6 @@ int ath_set_channel(struct ath_softc *sc, struct > ieee80211_hw *hw, > "Unable to reset channel (%u MHz), " > "reset status %d\n", > channel->center_freq, r); > - spin_unlock_bh(&sc->sc_pcu_lock); > goto ps_restore; > } > > @@ -276,12 +275,9 @@ int ath_set_channel(struct ath_softc *sc, struct > ieee80211_hw *hw, > ath_print(common, ATH_DBG_FATAL, > "Unable to restart recv logic\n"); > r = -EIO; > - spin_unlock_bh(&sc->sc_pcu_lock); > goto ps_restore; > } > > - spin_unlock_bh(&sc->sc_pcu_lock); > - > ath_update_txpow(sc); > ath9k_hw_set_interrupts(ah, ah->imask); > > @@ -292,6 +288,8 @@ int ath_set_channel(struct ath_softc *sc, struct > ieee80211_hw *hw, > } > > ps_restore: > + spin_unlock_bh(&sc->sc_pcu_lock); > + > ath9k_ps_restore(sc); > return r; > } > @@ -605,6 +603,8 @@ void ath9k_tasklet(unsigned long data) > return; > } > > + spin_lock_bh(&sc->sc_pcu_lock); > + > if (!ath9k_hw_check_alive(ah)) > ieee80211_queue_work(sc->hw, &sc->hw_check_work); > > @@ -615,15 +615,12 @@ void ath9k_tasklet(unsigned long data) > rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); > > if (status & rxmask) { > - spin_lock_bh(&sc->sc_pcu_lock); > - > /* Check for high priority Rx first */ > if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && > (status & ATH9K_INT_RXHP)) > ath_rx_tasklet(sc, 0, true); > > ath_rx_tasklet(sc, 0, false); > - spin_unlock_bh(&sc->sc_pcu_lock); > } > > if (status & ATH9K_INT_TX) { > @@ -649,6 +646,8 @@ void ath9k_tasklet(unsigned long data) > > /* re-enable hardware interrupt */ > ath9k_hw_enable_interrupts(ah); > + > + spin_unlock_bh(&sc->sc_pcu_lock); > ath9k_ps_restore(sc); > } > > @@ -876,12 +875,13 @@ void ath_radio_enable(struct ath_softc *sc, struct > ieee80211_hw *hw) > int r; > > ath9k_ps_wakeup(sc); > + spin_lock_bh(&sc->sc_pcu_lock); > + > ath9k_hw_configpcipowersave(ah, 0, 0); > > if (!ah->curchan) > ah->curchan = ath_get_curchannel(sc, sc->hw); > > - spin_lock_bh(&sc->sc_pcu_lock); > r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); > if (r) { > ath_print(common, ATH_DBG_FATAL, > @@ -897,8 +897,6 @@ void ath_radio_enable(struct ath_softc *sc, struct > ieee80211_hw *hw) > spin_unlock_bh(&sc->sc_pcu_lock); > return; > } > - spin_unlock_bh(&sc->sc_pcu_lock); > - > if (sc->sc_flags & SC_OP_BEACONS) > ath_beacon_config(sc, NULL); /* restart beacons */ > > @@ -911,6 +909,8 @@ void ath_radio_enable(struct ath_softc *sc, struct > ieee80211_hw *hw) > ath9k_hw_set_gpio(ah, ah->led_pin, 0); > > ieee80211_wake_queues(hw); > + spin_unlock_bh(&sc->sc_pcu_lock); > + > ath9k_ps_restore(sc); > } > > @@ -921,6 +921,8 @@ void ath_radio_disable(struct ath_softc *sc, struct > ieee80211_hw *hw) > int r; > > ath9k_ps_wakeup(sc); > + spin_lock_bh(&sc->sc_pcu_lock); > + > ieee80211_stop_queues(hw); > > /* > @@ -937,8 +939,6 @@ void ath_radio_disable(struct ath_softc *sc, struct > ieee80211_hw *hw) > > ath_drain_all_txq(sc, false); /* clear pending tx frames */ > > - spin_lock_bh(&sc->sc_pcu_lock); > - > ath_stoprecv(sc); /* turn off frame recv */ > ath_flushrecv(sc); /* flush recv queue */ > > @@ -955,10 +955,11 @@ void ath_radio_disable(struct ath_softc *sc, struct > ieee80211_hw *hw) > > ath9k_hw_phy_disable(ah); > > - spin_unlock_bh(&sc->sc_pcu_lock); > - > ath9k_hw_configpcipowersave(ah, 1, 1); > + > + spin_unlock_bh(&sc->sc_pcu_lock); > ath9k_ps_restore(sc); > + > ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); > } > > @@ -972,13 +973,13 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) > /* Stop ANI */ > del_timer_sync(&common->ani.timer); > > + spin_lock_bh(&sc->sc_pcu_lock); > + > ieee80211_stop_queues(hw); > > ath9k_hw_disable_interrupts(ah); > ath_drain_all_txq(sc, retry_tx); > > - spin_lock_bh(&sc->sc_pcu_lock); > - > ath_stoprecv(sc); > ath_flushrecv(sc); > > @@ -991,8 +992,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) > ath_print(common, ATH_DBG_FATAL, > "Unable to start recv logic\n"); > > - spin_unlock_bh(&sc->sc_pcu_lock); > - > /* > * We may be doing a reset in response to a request > * that changes the channel so update any state that > @@ -1017,6 +1016,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) > } > > ieee80211_wake_queues(hw); > + spin_unlock_bh(&sc->sc_pcu_lock); > > /* Start ANI */ > ath_start_ani(common); > @@ -1381,25 +1381,25 @@ static void ath9k_stop(struct ieee80211_hw *hw) > ath9k_btcoex_timer_pause(sc); > } > > + spin_lock_bh(&sc->sc_pcu_lock); > + > /* make sure h/w will not generate any interrupt > * before setting the invalid flag. */ > ath9k_hw_disable_interrupts(ah); > > if (!(sc->sc_flags & SC_OP_INVALID)) { > ath_drain_all_txq(sc, false); > - spin_lock_bh(&sc->sc_pcu_lock); > ath_stoprecv(sc); > ath9k_hw_phy_disable(ah); > - spin_unlock_bh(&sc->sc_pcu_lock); > - } else { > - spin_lock_bh(&sc->sc_pcu_lock); > + } else > sc->rx.rxlink = NULL; > - spin_unlock_bh(&sc->sc_pcu_lock); > - } > > /* disable HAL and put h/w to sleep */ > ath9k_hw_disable(ah); > ath9k_hw_configpcipowersave(ah, 1, 1); > + > + spin_unlock_bh(&sc->sc_pcu_lock); > + > ath9k_ps_restore(sc); > > /* Finally, put the chip in FULL SLEEP mode */ > diff --git a/drivers/net/wireless/ath/ath9k/xmit.c > b/drivers/net/wireless/ath/ath9k/xmit.c > index d97b7a3..2bc422e 100644 > --- a/drivers/net/wireless/ath/ath9k/xmit.c > +++ b/drivers/net/wireless/ath/ath9k/xmit.c > @@ -1148,13 +1148,11 @@ void ath_drain_all_txq(struct ath_softc *sc, bool > retry_tx) > ath_print(common, ATH_DBG_FATAL, > "Failed to stop TX DMA. Resetting hardware!\n"); > > - spin_lock_bh(&sc->sc_pcu_lock); > r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); > if (r) > ath_print(common, ATH_DBG_FATAL, > "Unable to reset hardware; reset status %d\n", > r); > - spin_unlock_bh(&sc->sc_pcu_lock); > } > > for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { > > _______________________________________________ > stable mailing list > [email protected] > http://linux.kernel.org/mailman/listinfo/stable _______________________________________________ stable mailing list [email protected] http://linux.kernel.org/mailman/listinfo/stable
