summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Copeland <me@bobcopeland.com>2010-07-13 17:32:41 +0200
committerJohn W. Linville <linville@tuxdriver.com>2010-07-14 19:52:46 +0200
commit450464def78c94018d997ae6f823578499cdf879 (patch)
tree2d6285b15042a77a3298a83eee0856050488ef8c
parentath5k: move reset to mac80211 workqueue (diff)
downloadlinux-450464def78c94018d997ae6f823578499cdf879.tar.xz
linux-450464def78c94018d997ae6f823578499cdf879.zip
ath5k: disable tasklets during reset
Based on a patch from Bruno Randolf, attempting useful work while we are resetting the chip just leads to interface lockups and bad descriptor data, and possibly DMAing to freed buffers. Let's suspend all tasklets while reprogramming the registers in the card to avoid such problems. In the future we can convert the tasklets to threaded interrupt handlers to simplify things. Signed-off-by: Bob Copeland <me@bobcopeland.com> Acked-by: Bruno Randolf <br1@einfach.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c20
1 files changed, 14 insertions, 6 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index b290cc6c600f..b0e1ca99fcad 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -2639,6 +2639,15 @@ ath5k_stop_locked(struct ath5k_softc *sc)
return 0;
}
+static void stop_tasklets(struct ath5k_softc *sc)
+{
+ tasklet_kill(&sc->rxtq);
+ tasklet_kill(&sc->txtq);
+ tasklet_kill(&sc->calib);
+ tasklet_kill(&sc->beacontq);
+ tasklet_kill(&sc->ani_tasklet);
+}
+
/*
* Stop the device, grabbing the top-level lock to protect
* against concurrent entry through ath5k_init (which can happen
@@ -2683,11 +2692,7 @@ ath5k_stop_hw(struct ath5k_softc *sc)
mmiowb();
mutex_unlock(&sc->lock);
- tasklet_kill(&sc->rxtq);
- tasklet_kill(&sc->txtq);
- tasklet_kill(&sc->calib);
- tasklet_kill(&sc->beacontq);
- tasklet_kill(&sc->ani_tasklet);
+ stop_tasklets(sc);
ath5k_rfkill_hw_stop(sc->ah);
@@ -2937,8 +2942,11 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
+ ath5k_hw_set_imr(ah, 0);
+ synchronize_irq(sc->pdev->irq);
+ stop_tasklets(sc);
+
if (chan) {
- ath5k_hw_set_imr(ah, 0);
ath5k_txq_cleanup(sc);
ath5k_rx_stop(sc);