mac80211: fix key flush handling in AP+STA
[oweals/openwrt.git] / package / kernel / mac80211 / patches / 317-ath9k-Check-for-active-GO-in-mgd_prepare_tx.patch
1 From: Sujith Manoharan <c_manoha@qca.qualcomm.com>
2 Date: Fri, 17 Oct 2014 07:40:22 +0530
3 Subject: [PATCH] ath9k: Check for active GO in mgd_prepare_tx()
4
5 If a GO interface is active when we receive a
6 mgd_prepare_tx() call, then we need to send
7 out a new NoA before switching to a new context.
8
9 Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
10 ---
11
12 --- a/drivers/net/wireless/ath/ath9k/ath9k.h
13 +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
14 @@ -385,6 +385,7 @@ struct ath_chanctx_sched {
15         bool wait_switch;
16         bool force_noa_update;
17         bool extend_absence;
18 +       bool mgd_prepare_tx;
19         enum ath_chanctx_state state;
20         u8 beacon_miss;
21  
22 @@ -977,6 +978,7 @@ struct ath_softc {
23         struct ath_chanctx_sched sched;
24         struct ath_offchannel offchannel;
25         struct ath_chanctx *next_chan;
26 +       struct completion go_beacon;
27  #endif
28  
29         unsigned long driver_data;
30 --- a/drivers/net/wireless/ath/ath9k/channel.c
31 +++ b/drivers/net/wireless/ath/ath9k/channel.c
32 @@ -421,6 +421,9 @@ void ath_chanctx_event(struct ath_softc 
33                                 "Move chanctx state from WAIT_FOR_TIMER to WAIT_FOR_BEACON\n");
34                 }
35  
36 +               if (sc->sched.mgd_prepare_tx)
37 +                       sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
38 +
39                 /*
40                  * When a context becomes inactive, for example,
41                  * disassociation of a station context, the NoA
42 @@ -547,6 +550,15 @@ void ath_chanctx_event(struct ath_softc 
43                 }
44  
45                 sc->sched.beacon_pending = false;
46 +
47 +               if (sc->sched.mgd_prepare_tx) {
48 +                       sc->sched.mgd_prepare_tx = false;
49 +                       complete(&sc->go_beacon);
50 +                       ath_dbg(common, CHAN_CTX,
51 +                               "Beacon sent, complete go_beacon\n");
52 +                       break;
53 +               }
54 +
55                 if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
56                         break;
57  
58 @@ -1263,6 +1275,8 @@ void ath9k_init_channel_context(struct a
59                     (unsigned long)sc);
60         setup_timer(&sc->sched.timer, ath_chanctx_timer,
61                     (unsigned long)sc);
62 +
63 +       init_completion(&sc->go_beacon);
64  }
65  
66  void ath9k_deinit_channel_context(struct ath_softc *sc)
67 --- a/drivers/net/wireless/ath/ath9k/main.c
68 +++ b/drivers/net/wireless/ath/ath9k/main.c
69 @@ -2474,7 +2474,11 @@ static void ath9k_mgd_prepare_tx(struct 
70         struct ath_softc *sc = hw->priv;
71         struct ath_common *common = ath9k_hw_common(sc->sc_ah);
72         struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
73 +       struct ath_beacon_config *cur_conf;
74 +       struct ath_chanctx *go_ctx;
75 +       unsigned long timeout;
76         bool changed = false;
77 +       u32 beacon_int;
78  
79         if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
80                 return;
81 @@ -2485,19 +2489,46 @@ static void ath9k_mgd_prepare_tx(struct 
82         mutex_lock(&sc->mutex);
83  
84         spin_lock_bh(&sc->chan_lock);
85 -       if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
86 -               sc->next_chan = avp->chanctx;
87 +       if (sc->next_chan || (sc->cur_chan != avp->chanctx))
88                 changed = true;
89 +       spin_unlock_bh(&sc->chan_lock);
90 +
91 +       if (!changed)
92 +               goto out;
93 +
94 +       go_ctx = ath_is_go_chanctx_present(sc);
95 +
96 +       if (go_ctx) {
97 +               /*
98 +                * Wait till the GO interface gets a chance
99 +                * to send out an NoA.
100 +                */
101 +               spin_lock_bh(&sc->chan_lock);
102 +               sc->sched.mgd_prepare_tx = true;
103 +               cur_conf = &go_ctx->beacon;
104 +               beacon_int = TU_TO_USEC(cur_conf->beacon_interval);
105 +               spin_unlock_bh(&sc->chan_lock);
106 +
107 +               timeout = usecs_to_jiffies(beacon_int);
108 +               init_completion(&sc->go_beacon);
109 +
110 +               if (wait_for_completion_timeout(&sc->go_beacon,
111 +                                               timeout) == 0)
112 +                       ath_dbg(common, CHAN_CTX,
113 +                               "Failed to send new NoA\n");
114         }
115 +
116         ath_dbg(common, CHAN_CTX,
117 -               "%s: Set chanctx state to FORCE_ACTIVE, changed: %d\n",
118 -               __func__, changed);
119 +               "%s: Set chanctx state to FORCE_ACTIVE for vif: %pM\n",
120 +               __func__, vif->addr);
121 +
122 +       spin_lock_bh(&sc->chan_lock);
123 +       sc->next_chan = avp->chanctx;
124         sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
125         spin_unlock_bh(&sc->chan_lock);
126  
127 -       if (changed)
128 -               ath_chanctx_set_next(sc, true);
129 -
130 +       ath_chanctx_set_next(sc, true);
131 +out:
132         mutex_unlock(&sc->mutex);
133  }
134