Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae2ff239 authored by Sujith Manoharan's avatar Sujith Manoharan Committed by John W. Linville
Browse files

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: default avatarSujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 5555c955
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -598,10 +598,17 @@ irqreturn_t ath_isr(int irq, void *dev)
#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, struct ath9k_channel *hchan)
	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);