aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/main.c
diff options
context:
space:
mode:
authorSujith Manoharan <c_manoha@qca.qualcomm.com>2014-10-16 22:10:12 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-10-27 14:16:14 -0400
commitae2ff23930d78ff619852c47a4b89aef5a26ef2b (patch)
tree79962d5c0efa616634d6967dc10fee8f95c8b30f /drivers/net/wireless/ath/ath9k/main.c
parent5555c955249b0d942e8ae066e80a24237b16e7f8 (diff)
ath9k: Set ATH_OP_HW_RESET before HW reset
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@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/main.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index eb6ba9f8d9ff..dda09ba321d7 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -598,10 +598,17 @@ chip_reset:
598#undef SCHED_INTR 598#undef SCHED_INTR
599} 599}
600 600
601/*
602 * This function is called when a HW reset cannot be deferred
603 * and has to be immediate.
604 */
601int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan) 605int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
602{ 606{
607 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
603 int r; 608 int r;
604 609
610 set_bit(ATH_OP_HW_RESET, &common->op_flags);
611
605 ath9k_ps_wakeup(sc); 612 ath9k_ps_wakeup(sc);
606 r = ath_reset_internal(sc, hchan); 613 r = ath_reset_internal(sc, hchan);
607 ath9k_ps_restore(sc); 614 ath9k_ps_restore(sc);
@@ -609,6 +616,11 @@ int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
609 return r; 616 return r;
610} 617}
611 618
619/*
620 * When a HW reset can be deferred, it is added to the
621 * hw_reset_work workqueue, but we set ATH_OP_HW_RESET before
622 * queueing.
623 */
612void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type) 624void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
613{ 625{
614 struct ath_common *common = ath9k_hw_common(sc->sc_ah); 626 struct ath_common *common = ath9k_hw_common(sc->sc_ah);