ath9k: do not access hardware on IRQs during reset
Instead of killing interrupts during reset when the first one happens,
kill them before issuing the reset.
This fixes an easy to reproduce crash with multiple cards sharing the
same IRQ.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index d41e6cf..cff070d 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -512,15 +512,12 @@
if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags))
return IRQ_NONE;
- /* shared irq, not for us */
-
- if (!ath9k_hw_intrpend(ah))
+ if (!AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
return IRQ_NONE;
- if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
- ath9k_hw_kill_interrupts(ah);
- return IRQ_HANDLED;
- }
+ /* shared irq, not for us */
+ if (!ath9k_hw_intrpend(ah))
+ return IRQ_NONE;
/*
* Figure out the reason(s) for the interrupt. Note
@@ -532,6 +529,9 @@
ath9k_debug_sync_cause(sc, sync_cause);
status &= ah->imask; /* discard unasked-for bits */
+ if (AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
+ return IRQ_HANDLED;
+
/*
* If there are no status bits set, then this interrupt was not
* for me (should have been caught above).
@@ -613,6 +613,7 @@
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int r;
+ ath9k_hw_kill_interrupts(sc->sc_ah);
set_bit(ATH_OP_HW_RESET, &common->op_flags);
ath9k_ps_wakeup(sc);
@@ -633,6 +634,7 @@
#ifdef CONFIG_ATH9K_DEBUGFS
RESET_STAT_INC(sc, type);
#endif
+ ath9k_hw_kill_interrupts(sc->sc_ah);
set_bit(ATH_OP_HW_RESET, &common->op_flags);
ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
}