aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2014-11-30 15:58:32 -0500
committerJohn W. Linville <linville@tuxdriver.com>2014-12-01 15:57:22 -0500
commit872b5d814f99a91bdf92d96265663882b014403d (patch)
tree158cf57a112cc29a05821ec2f4ae7171ff65a174
parentef739ab6aac38b25e473f418ecfe1fb433346fa1 (diff)
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>
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c14
1 files changed, 8 insertions, 6 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index d41e6cfd24b1..cff070d7a325 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -512,16 +512,13 @@ irqreturn_t ath_isr(int irq, void *dev)
512 if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags)) 512 if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags))
513 return IRQ_NONE; 513 return IRQ_NONE;
514 514
515 /* shared irq, not for us */ 515 if (!AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
516 return IRQ_NONE;
516 517
518 /* shared irq, not for us */
517 if (!ath9k_hw_intrpend(ah)) 519 if (!ath9k_hw_intrpend(ah))
518 return IRQ_NONE; 520 return IRQ_NONE;
519 521
520 if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
521 ath9k_hw_kill_interrupts(ah);
522 return IRQ_HANDLED;
523 }
524
525 /* 522 /*
526 * Figure out the reason(s) for the interrupt. Note 523 * Figure out the reason(s) for the interrupt. Note
527 * that the hal returns a pseudo-ISR that may include 524 * that the hal returns a pseudo-ISR that may include
@@ -532,6 +529,9 @@ irqreturn_t ath_isr(int irq, void *dev)
532 ath9k_debug_sync_cause(sc, sync_cause); 529 ath9k_debug_sync_cause(sc, sync_cause);
533 status &= ah->imask; /* discard unasked-for bits */ 530 status &= ah->imask; /* discard unasked-for bits */
534 531
532 if (AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
533 return IRQ_HANDLED;
534
535 /* 535 /*
536 * If there are no status bits set, then this interrupt was not 536 * If there are no status bits set, then this interrupt was not
537 * for me (should have been caught above). 537 * for me (should have been caught above).
@@ -613,6 +613,7 @@ int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
613 struct ath_common *common = ath9k_hw_common(sc->sc_ah); 613 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
614 int r; 614 int r;
615 615
616 ath9k_hw_kill_interrupts(sc->sc_ah);
616 set_bit(ATH_OP_HW_RESET, &common->op_flags); 617 set_bit(ATH_OP_HW_RESET, &common->op_flags);
617 618
618 ath9k_ps_wakeup(sc); 619 ath9k_ps_wakeup(sc);
@@ -633,6 +634,7 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
633#ifdef CONFIG_ATH9K_DEBUGFS 634#ifdef CONFIG_ATH9K_DEBUGFS
634 RESET_STAT_INC(sc, type); 635 RESET_STAT_INC(sc, type);
635#endif 636#endif
637 ath9k_hw_kill_interrupts(sc->sc_ah);
636 set_bit(ATH_OP_HW_RESET, &common->op_flags); 638 set_bit(ATH_OP_HW_RESET, &common->op_flags);
637 ieee80211_queue_work(sc->hw, &sc->hw_reset_work); 639 ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
638} 640}