From: Sujith Manoharan <c_manoha@xxxxxxxxxxxxxxxx> When a HW reset is done, the interrupt tasklet is disabled before ISRs are disabled in the HW. This allows a small window where the HW can still generate interrupts. Since the tasklet is disabled and not killed, it is not scheduled but deferred for execution at a later time. This happens because ATH_OP_HW_RESET is not set when ath_reset() is called. When the hw_reset_work workqueue is used, this problem doesn't arise because ATH_OP_HW_RESET is set and the ISR bails out. Set ATH_OP_HW_RESET properly in ath_reset() to avoid this race - all the ath_reset_internal() callers have been converted to use ath_reset() in the previous patch. Signed-off-by: Sujith Manoharan <c_manoha@xxxxxxxxxxxxxxxx> --- drivers/net/wireless/ath/ath9k/main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index eb6ba9f..dda09ba 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -598,10 +598,17 @@ chip_reset: #undef SCHED_INTR } +/* + * This function is called when a HW reset cannot be deferred + * and has to be immediate. + */ int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); int r; + set_bit(ATH_OP_HW_RESET, &common->op_flags); + ath9k_ps_wakeup(sc); r = ath_reset_internal(sc, hchan); ath9k_ps_restore(sc); @@ -609,6 +616,11 @@ int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan) return r; } +/* + * When a HW reset can be deferred, it is added to the + * hw_reset_work workqueue, but we set ATH_OP_HW_RESET before + * queueing. + */ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); -- 2.1.2 -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html