f0d9e712e4
Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 42952
55 lines
1.7 KiB
Diff
55 lines
1.7 KiB
Diff
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);
|