12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455 |
- From: Sujith Manoharan <[email protected]>
- 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 <[email protected]>
- ---
- --- 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);
|