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

ath9k: fix interrupt storms on queued hardware reset

commit b74713d0
"ath9k: Handle fatal interrupts properly" introduced a race condition, where
IRQs are being left enabled, however the irq handler returns IRQ_HANDLED
while the reset is still queued without addressing the IRQ cause.
This leads to an IRQ storm that prevents the system from even getting to
the reset code.

Fix this by disabling IRQs in the handler without touching intr_ref_cnt.

Cc: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
Cc: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent bbf2e652
...@@ -773,15 +773,10 @@ bool ath9k_hw_intrpend(struct ath_hw *ah) ...@@ -773,15 +773,10 @@ bool ath9k_hw_intrpend(struct ath_hw *ah)
} }
EXPORT_SYMBOL(ath9k_hw_intrpend); EXPORT_SYMBOL(ath9k_hw_intrpend);
void ath9k_hw_disable_interrupts(struct ath_hw *ah) void ath9k_hw_kill_interrupts(struct ath_hw *ah)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
if (!(ah->imask & ATH9K_INT_GLOBAL))
atomic_set(&ah->intr_ref_cnt, -1);
else
atomic_dec(&ah->intr_ref_cnt);
ath_dbg(common, INTERRUPT, "disable IER\n"); ath_dbg(common, INTERRUPT, "disable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_DISABLE); REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
(void) REG_READ(ah, AR_IER); (void) REG_READ(ah, AR_IER);
...@@ -793,6 +788,17 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah) ...@@ -793,6 +788,17 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah)
(void) REG_READ(ah, AR_INTR_SYNC_ENABLE); (void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
} }
} }
EXPORT_SYMBOL(ath9k_hw_kill_interrupts);
void ath9k_hw_disable_interrupts(struct ath_hw *ah)
{
if (!(ah->imask & ATH9K_INT_GLOBAL))
atomic_set(&ah->intr_ref_cnt, -1);
else
atomic_dec(&ah->intr_ref_cnt);
ath9k_hw_kill_interrupts(ah);
}
EXPORT_SYMBOL(ath9k_hw_disable_interrupts); EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
void ath9k_hw_enable_interrupts(struct ath_hw *ah) void ath9k_hw_enable_interrupts(struct ath_hw *ah)
......
...@@ -738,6 +738,7 @@ bool ath9k_hw_intrpend(struct ath_hw *ah); ...@@ -738,6 +738,7 @@ bool ath9k_hw_intrpend(struct ath_hw *ah);
void ath9k_hw_set_interrupts(struct ath_hw *ah); void ath9k_hw_set_interrupts(struct ath_hw *ah);
void ath9k_hw_enable_interrupts(struct ath_hw *ah); void ath9k_hw_enable_interrupts(struct ath_hw *ah);
void ath9k_hw_disable_interrupts(struct ath_hw *ah); void ath9k_hw_disable_interrupts(struct ath_hw *ah);
void ath9k_hw_kill_interrupts(struct ath_hw *ah);
void ar9002_hw_attach_mac_ops(struct ath_hw *ah); void ar9002_hw_attach_mac_ops(struct ath_hw *ah);
......
...@@ -462,8 +462,10 @@ irqreturn_t ath_isr(int irq, void *dev) ...@@ -462,8 +462,10 @@ irqreturn_t ath_isr(int irq, void *dev)
if (!ath9k_hw_intrpend(ah)) if (!ath9k_hw_intrpend(ah))
return IRQ_NONE; return IRQ_NONE;
if(test_bit(SC_OP_HW_RESET, &sc->sc_flags)) if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) {
ath9k_hw_kill_interrupts(ah);
return IRQ_HANDLED; return IRQ_HANDLED;
}
/* /*
* Figure out the reason(s) for the interrupt. Note * Figure out the reason(s) for the interrupt. Note
......
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