mac80211: update to 2014-10-08
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / 307-ath9k-Set-ATH_OP_HW_RESET-before-HW-reset.patch
1 From: Sujith Manoharan <c_manoha@qca.qualcomm.com>
2 Date: Fri, 17 Oct 2014 07:40:12 +0530
3 Subject: [PATCH] ath9k: Set ATH_OP_HW_RESET before HW reset
4
5 When a HW reset is done, the interrupt tasklet is
6 disabled before ISRs are disabled in the HW. This
7 allows a small window where the HW can still generate
8 interrupts. Since the tasklet is disabled and not killed,
9 it is not scheduled but deferred for execution at a later
10 time.
11
12 This happens because ATH_OP_HW_RESET is not set when ath_reset()
13 is called. When the hw_reset_work workqueue is used, this
14 problem doesn't arise because ATH_OP_HW_RESET is set
15 and the ISR bails out.
16
17 Set ATH_OP_HW_RESET properly in ath_reset() to avoid
18 this race - all the ath_reset_internal() callers have
19 been converted to use ath_reset() in the previous patch.
20
21 Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
22 ---
23
24 --- a/drivers/net/wireless/ath/ath9k/main.c
25 +++ b/drivers/net/wireless/ath/ath9k/main.c
26 @@ -598,10 +598,17 @@ chip_reset:
27 #undef SCHED_INTR
28 }
29
30 +/*
31 + * This function is called when a HW reset cannot be deferred
32 + * and has to be immediate.
33 + */
34 int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
35 {
36 + struct ath_common *common = ath9k_hw_common(sc->sc_ah);
37 int r;
38
39 + set_bit(ATH_OP_HW_RESET, &common->op_flags);
40 +
41 ath9k_ps_wakeup(sc);
42 r = ath_reset_internal(sc, hchan);
43 ath9k_ps_restore(sc);
44 @@ -609,6 +616,11 @@ int ath_reset(struct ath_softc *sc, stru
45 return r;
46 }
47
48 +/*
49 + * When a HW reset can be deferred, it is added to the
50 + * hw_reset_work workqueue, but we set ATH_OP_HW_RESET before
51 + * queueing.
52 + */
53 void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
54 {
55 struct ath_common *common = ath9k_hw_common(sc->sc_ah);