summaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/307-ath9k-Set-ATH_OP_HW_RESET-before-HW-reset.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/kernel/mac80211/patches/307-ath9k-Set-ATH_OP_HW_RESET-before-HW-reset.patch')
-rw-r--r--package/kernel/mac80211/patches/307-ath9k-Set-ATH_OP_HW_RESET-before-HW-reset.patch55
1 files changed, 55 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/307-ath9k-Set-ATH_OP_HW_RESET-before-HW-reset.patch b/package/kernel/mac80211/patches/307-ath9k-Set-ATH_OP_HW_RESET-before-HW-reset.patch
new file mode 100644
index 0000000000..75a2ab5878
--- /dev/null
+++ b/package/kernel/mac80211/patches/307-ath9k-Set-ATH_OP_HW_RESET-before-HW-reset.patch
@@ -0,0 +1,55 @@
+From: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date: Fri, 17 Oct 2014 07:40:12 +0530
+Subject: [PATCH] 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>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -598,10 +598,17 @@ chip_reset:
+ #undef SCHED_INTR
+ }
+
++/*
++ * This function is called when a HW reset cannot be deferred
++ * and has to be immediate.
++ */
+ int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
+ {
++ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ int r;
+
++ set_bit(ATH_OP_HW_RESET, &common->op_flags);
++
+ ath9k_ps_wakeup(sc);
+ r = ath_reset_internal(sc, hchan);
+ ath9k_ps_restore(sc);
+@@ -609,6 +616,11 @@ int ath_reset(struct ath_softc *sc, stru
+ return r;
+ }
+
++/*
++ * When a HW reset can be deferred, it is added to the
++ * hw_reset_work workqueue, but we set ATH_OP_HW_RESET before
++ * queueing.
++ */
+ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
+ {
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);