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>
This commit is contained in:
parent
5555c95524
commit
ae2ff23930
|
@ -598,10 +598,17 @@ chip_reset:
|
||||||
#undef SCHED_INTR
|
#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)
|
int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
|
||||||
{
|
{
|
||||||
|
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
set_bit(ATH_OP_HW_RESET, &common->op_flags);
|
||||||
|
|
||||||
ath9k_ps_wakeup(sc);
|
ath9k_ps_wakeup(sc);
|
||||||
r = ath_reset_internal(sc, hchan);
|
r = ath_reset_internal(sc, hchan);
|
||||||
ath9k_ps_restore(sc);
|
ath9k_ps_restore(sc);
|
||||||
|
@ -609,6 +616,11 @@ int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
|
||||||
return r;
|
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)
|
void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
|
||||||
{
|
{
|
||||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||||
|
|
Loading…
Reference in a new issue