Commit 872b5d81 authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville

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: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent ef739ab6
...@@ -512,16 +512,13 @@ irqreturn_t ath_isr(int irq, void *dev) ...@@ -512,16 +512,13 @@ irqreturn_t ath_isr(int irq, void *dev)
if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags)) if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags))
return IRQ_NONE; return IRQ_NONE;
/* shared irq, not for us */ if (!AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
return IRQ_NONE;
/* shared irq, not for us */
if (!ath9k_hw_intrpend(ah)) if (!ath9k_hw_intrpend(ah))
return IRQ_NONE; return IRQ_NONE;
if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
ath9k_hw_kill_interrupts(ah);
return IRQ_HANDLED;
}
/* /*
* Figure out the reason(s) for the interrupt. Note * Figure out the reason(s) for the interrupt. Note
* that the hal returns a pseudo-ISR that may include * that the hal returns a pseudo-ISR that may include
...@@ -532,6 +529,9 @@ irqreturn_t ath_isr(int irq, void *dev) ...@@ -532,6 +529,9 @@ irqreturn_t ath_isr(int irq, void *dev)
ath9k_debug_sync_cause(sc, sync_cause); ath9k_debug_sync_cause(sc, sync_cause);
status &= ah->imask; /* discard unasked-for bits */ 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 * If there are no status bits set, then this interrupt was not
* for me (should have been caught above). * for me (should have been caught above).
...@@ -613,6 +613,7 @@ int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan) ...@@ -613,6 +613,7 @@ int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int r; int r;
ath9k_hw_kill_interrupts(sc->sc_ah);
set_bit(ATH_OP_HW_RESET, &common->op_flags); set_bit(ATH_OP_HW_RESET, &common->op_flags);
ath9k_ps_wakeup(sc); ath9k_ps_wakeup(sc);
...@@ -633,6 +634,7 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type) ...@@ -633,6 +634,7 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
#ifdef CONFIG_ATH9K_DEBUGFS #ifdef CONFIG_ATH9K_DEBUGFS
RESET_STAT_INC(sc, type); RESET_STAT_INC(sc, type);
#endif #endif
ath9k_hw_kill_interrupts(sc->sc_ah);
set_bit(ATH_OP_HW_RESET, &common->op_flags); set_bit(ATH_OP_HW_RESET, &common->op_flags);
ieee80211_queue_work(sc->hw, &sc->hw_reset_work); ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment