Commit b25bfda38236f349cde0d1b28952f4eea2148d3f
Committed by
John W. Linville
1 parent
f9dc73e541
Exists in
master
and in
6 other branches
ath9k: Fix kernel panic in AR2427 in AP mode
don't do aggregation related stuff for 'AP mode client power save handling' if aggregation is not enabled in the driver, otherwise it will lead to panic because those data structures won't be never intialized in 'ath_tx_node_init' if aggregation is disabled EIP is at ath_tx_aggr_wakeup+0x37/0x80 [ath9k] EAX: e8c09a20 EBX: f2a304e8 ECX: 00000001 EDX: 00000000 ESI: e8c085e0 EDI: f2a304ac EBP: f40e1ca4 ESP: f40e1c8c DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 Process swapper/1 (pid: 0, ti=f40e0000 task=f408e860 task.ti=f40dc000) Stack: 0001e966 e8c09a20 00000000 f2a304ac e8c085e0 f2a304ac f40e1cb0 f8186741 f8186700 f40e1d2c f922988d f2a304ac 00000202 00000001 c0b4ba43 00000000 0000000f e8eb75c0 e8c085e0 205b0001 34383220 f2a304ac f2a30000 00010020 Call Trace: [<f8186741>] ath9k_sta_notify+0x41/0x50 [ath9k] [<f8186700>] ? ath9k_get_survey+0x110/0x110 [ath9k] [<f922988d>] ieee80211_sta_ps_deliver_wakeup+0x9d/0x350 [mac80211] [<c018dc75>] ? __module_address+0x95/0xb0 [<f92465b3>] ap_sta_ps_end+0x63/0xa0 [mac80211] [<f9246746>] ieee80211_rx_h_sta_process+0x156/0x2b0 [mac80211] [<f9247d1e>] ieee80211_rx_handlers+0xce/0x510 [mac80211] [<c018440b>] ? trace_hardirqs_on+0xb/0x10 [<c056936e>] ? skb_queue_tail+0x3e/0x50 [<f9248271>] ieee80211_prepare_and_rx_handle+0x111/0x750 [mac80211] [<f9248bf9>] ieee80211_rx+0x349/0xb20 [mac80211] [<f9248949>] ? ieee80211_rx+0x99/0xb20 [mac80211] [<f818b0b8>] ath_rx_tasklet+0x818/0x1d00 [ath9k] [<f8187a75>] ? ath9k_tasklet+0x35/0x1c0 [ath9k] [<f8187a75>] ? ath9k_tasklet+0x35/0x1c0 [ath9k] [<f8187b33>] ath9k_tasklet+0xf3/0x1c0 [ath9k] [<c0151b7e>] tasklet_action+0xbe/0x180 Cc: stable@kernel.org Cc: Senthil Balasubramanian <senthilb@qca.qualcomm.com> Cc: Rajkumar Manoharan <rmanohar@qca.qualcomm.com> Reported-by: Ashwin Mendonca <ashwinloyal@gmail.com> Tested-by: Ashwin Mendonca <ashwinloyal@gmail.com> Signed-off-by: Mohammed Shafi Shajakhan <mohammed@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Showing 1 changed file with 3 additions and 0 deletions Inline Diff
drivers/net/wireless/ath/ath9k/main.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2008-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2011 Atheros Communications Inc. |
3 | * | 3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. | 6 | * copyright notice and this permission notice appear in all copies. |
7 | * | 7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/nl80211.h> | 17 | #include <linux/nl80211.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include "ath9k.h" | 19 | #include "ath9k.h" |
20 | #include "btcoex.h" | 20 | #include "btcoex.h" |
21 | 21 | ||
22 | static u8 parse_mpdudensity(u8 mpdudensity) | 22 | static u8 parse_mpdudensity(u8 mpdudensity) |
23 | { | 23 | { |
24 | /* | 24 | /* |
25 | * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": | 25 | * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": |
26 | * 0 for no restriction | 26 | * 0 for no restriction |
27 | * 1 for 1/4 us | 27 | * 1 for 1/4 us |
28 | * 2 for 1/2 us | 28 | * 2 for 1/2 us |
29 | * 3 for 1 us | 29 | * 3 for 1 us |
30 | * 4 for 2 us | 30 | * 4 for 2 us |
31 | * 5 for 4 us | 31 | * 5 for 4 us |
32 | * 6 for 8 us | 32 | * 6 for 8 us |
33 | * 7 for 16 us | 33 | * 7 for 16 us |
34 | */ | 34 | */ |
35 | switch (mpdudensity) { | 35 | switch (mpdudensity) { |
36 | case 0: | 36 | case 0: |
37 | return 0; | 37 | return 0; |
38 | case 1: | 38 | case 1: |
39 | case 2: | 39 | case 2: |
40 | case 3: | 40 | case 3: |
41 | /* Our lower layer calculations limit our precision to | 41 | /* Our lower layer calculations limit our precision to |
42 | 1 microsecond */ | 42 | 1 microsecond */ |
43 | return 1; | 43 | return 1; |
44 | case 4: | 44 | case 4: |
45 | return 2; | 45 | return 2; |
46 | case 5: | 46 | case 5: |
47 | return 4; | 47 | return 4; |
48 | case 6: | 48 | case 6: |
49 | return 8; | 49 | return 8; |
50 | case 7: | 50 | case 7: |
51 | return 16; | 51 | return 16; |
52 | default: | 52 | default: |
53 | return 0; | 53 | return 0; |
54 | } | 54 | } |
55 | } | 55 | } |
56 | 56 | ||
57 | static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq) | 57 | static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq) |
58 | { | 58 | { |
59 | bool pending = false; | 59 | bool pending = false; |
60 | 60 | ||
61 | spin_lock_bh(&txq->axq_lock); | 61 | spin_lock_bh(&txq->axq_lock); |
62 | 62 | ||
63 | if (txq->axq_depth || !list_empty(&txq->axq_acq)) | 63 | if (txq->axq_depth || !list_empty(&txq->axq_acq)) |
64 | pending = true; | 64 | pending = true; |
65 | 65 | ||
66 | spin_unlock_bh(&txq->axq_lock); | 66 | spin_unlock_bh(&txq->axq_lock); |
67 | return pending; | 67 | return pending; |
68 | } | 68 | } |
69 | 69 | ||
70 | static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) | 70 | static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) |
71 | { | 71 | { |
72 | unsigned long flags; | 72 | unsigned long flags; |
73 | bool ret; | 73 | bool ret; |
74 | 74 | ||
75 | spin_lock_irqsave(&sc->sc_pm_lock, flags); | 75 | spin_lock_irqsave(&sc->sc_pm_lock, flags); |
76 | ret = ath9k_hw_setpower(sc->sc_ah, mode); | 76 | ret = ath9k_hw_setpower(sc->sc_ah, mode); |
77 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | 77 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); |
78 | 78 | ||
79 | return ret; | 79 | return ret; |
80 | } | 80 | } |
81 | 81 | ||
82 | void ath9k_ps_wakeup(struct ath_softc *sc) | 82 | void ath9k_ps_wakeup(struct ath_softc *sc) |
83 | { | 83 | { |
84 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 84 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
85 | unsigned long flags; | 85 | unsigned long flags; |
86 | enum ath9k_power_mode power_mode; | 86 | enum ath9k_power_mode power_mode; |
87 | 87 | ||
88 | spin_lock_irqsave(&sc->sc_pm_lock, flags); | 88 | spin_lock_irqsave(&sc->sc_pm_lock, flags); |
89 | if (++sc->ps_usecount != 1) | 89 | if (++sc->ps_usecount != 1) |
90 | goto unlock; | 90 | goto unlock; |
91 | 91 | ||
92 | power_mode = sc->sc_ah->power_mode; | 92 | power_mode = sc->sc_ah->power_mode; |
93 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); | 93 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); |
94 | 94 | ||
95 | /* | 95 | /* |
96 | * While the hardware is asleep, the cycle counters contain no | 96 | * While the hardware is asleep, the cycle counters contain no |
97 | * useful data. Better clear them now so that they don't mess up | 97 | * useful data. Better clear them now so that they don't mess up |
98 | * survey data results. | 98 | * survey data results. |
99 | */ | 99 | */ |
100 | if (power_mode != ATH9K_PM_AWAKE) { | 100 | if (power_mode != ATH9K_PM_AWAKE) { |
101 | spin_lock(&common->cc_lock); | 101 | spin_lock(&common->cc_lock); |
102 | ath_hw_cycle_counters_update(common); | 102 | ath_hw_cycle_counters_update(common); |
103 | memset(&common->cc_survey, 0, sizeof(common->cc_survey)); | 103 | memset(&common->cc_survey, 0, sizeof(common->cc_survey)); |
104 | spin_unlock(&common->cc_lock); | 104 | spin_unlock(&common->cc_lock); |
105 | } | 105 | } |
106 | 106 | ||
107 | unlock: | 107 | unlock: |
108 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | 108 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); |
109 | } | 109 | } |
110 | 110 | ||
111 | void ath9k_ps_restore(struct ath_softc *sc) | 111 | void ath9k_ps_restore(struct ath_softc *sc) |
112 | { | 112 | { |
113 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 113 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
114 | enum ath9k_power_mode mode; | 114 | enum ath9k_power_mode mode; |
115 | unsigned long flags; | 115 | unsigned long flags; |
116 | 116 | ||
117 | spin_lock_irqsave(&sc->sc_pm_lock, flags); | 117 | spin_lock_irqsave(&sc->sc_pm_lock, flags); |
118 | if (--sc->ps_usecount != 0) | 118 | if (--sc->ps_usecount != 0) |
119 | goto unlock; | 119 | goto unlock; |
120 | 120 | ||
121 | if (sc->ps_idle) | 121 | if (sc->ps_idle) |
122 | mode = ATH9K_PM_FULL_SLEEP; | 122 | mode = ATH9K_PM_FULL_SLEEP; |
123 | else if (sc->ps_enabled && | 123 | else if (sc->ps_enabled && |
124 | !(sc->ps_flags & (PS_WAIT_FOR_BEACON | | 124 | !(sc->ps_flags & (PS_WAIT_FOR_BEACON | |
125 | PS_WAIT_FOR_CAB | | 125 | PS_WAIT_FOR_CAB | |
126 | PS_WAIT_FOR_PSPOLL_DATA | | 126 | PS_WAIT_FOR_PSPOLL_DATA | |
127 | PS_WAIT_FOR_TX_ACK))) | 127 | PS_WAIT_FOR_TX_ACK))) |
128 | mode = ATH9K_PM_NETWORK_SLEEP; | 128 | mode = ATH9K_PM_NETWORK_SLEEP; |
129 | else | 129 | else |
130 | goto unlock; | 130 | goto unlock; |
131 | 131 | ||
132 | spin_lock(&common->cc_lock); | 132 | spin_lock(&common->cc_lock); |
133 | ath_hw_cycle_counters_update(common); | 133 | ath_hw_cycle_counters_update(common); |
134 | spin_unlock(&common->cc_lock); | 134 | spin_unlock(&common->cc_lock); |
135 | 135 | ||
136 | ath9k_hw_setpower(sc->sc_ah, mode); | 136 | ath9k_hw_setpower(sc->sc_ah, mode); |
137 | 137 | ||
138 | unlock: | 138 | unlock: |
139 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | 139 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); |
140 | } | 140 | } |
141 | 141 | ||
142 | void ath_start_ani(struct ath_common *common) | 142 | void ath_start_ani(struct ath_common *common) |
143 | { | 143 | { |
144 | struct ath_hw *ah = common->ah; | 144 | struct ath_hw *ah = common->ah; |
145 | unsigned long timestamp = jiffies_to_msecs(jiffies); | 145 | unsigned long timestamp = jiffies_to_msecs(jiffies); |
146 | struct ath_softc *sc = (struct ath_softc *) common->priv; | 146 | struct ath_softc *sc = (struct ath_softc *) common->priv; |
147 | 147 | ||
148 | if (!(sc->sc_flags & SC_OP_ANI_RUN)) | 148 | if (!(sc->sc_flags & SC_OP_ANI_RUN)) |
149 | return; | 149 | return; |
150 | 150 | ||
151 | if (sc->sc_flags & SC_OP_OFFCHANNEL) | 151 | if (sc->sc_flags & SC_OP_OFFCHANNEL) |
152 | return; | 152 | return; |
153 | 153 | ||
154 | common->ani.longcal_timer = timestamp; | 154 | common->ani.longcal_timer = timestamp; |
155 | common->ani.shortcal_timer = timestamp; | 155 | common->ani.shortcal_timer = timestamp; |
156 | common->ani.checkani_timer = timestamp; | 156 | common->ani.checkani_timer = timestamp; |
157 | 157 | ||
158 | mod_timer(&common->ani.timer, | 158 | mod_timer(&common->ani.timer, |
159 | jiffies + | 159 | jiffies + |
160 | msecs_to_jiffies((u32)ah->config.ani_poll_interval)); | 160 | msecs_to_jiffies((u32)ah->config.ani_poll_interval)); |
161 | } | 161 | } |
162 | 162 | ||
163 | static void ath_update_survey_nf(struct ath_softc *sc, int channel) | 163 | static void ath_update_survey_nf(struct ath_softc *sc, int channel) |
164 | { | 164 | { |
165 | struct ath_hw *ah = sc->sc_ah; | 165 | struct ath_hw *ah = sc->sc_ah; |
166 | struct ath9k_channel *chan = &ah->channels[channel]; | 166 | struct ath9k_channel *chan = &ah->channels[channel]; |
167 | struct survey_info *survey = &sc->survey[channel]; | 167 | struct survey_info *survey = &sc->survey[channel]; |
168 | 168 | ||
169 | if (chan->noisefloor) { | 169 | if (chan->noisefloor) { |
170 | survey->filled |= SURVEY_INFO_NOISE_DBM; | 170 | survey->filled |= SURVEY_INFO_NOISE_DBM; |
171 | survey->noise = ath9k_hw_getchan_noise(ah, chan); | 171 | survey->noise = ath9k_hw_getchan_noise(ah, chan); |
172 | } | 172 | } |
173 | } | 173 | } |
174 | 174 | ||
175 | /* | 175 | /* |
176 | * Updates the survey statistics and returns the busy time since last | 176 | * Updates the survey statistics and returns the busy time since last |
177 | * update in %, if the measurement duration was long enough for the | 177 | * update in %, if the measurement duration was long enough for the |
178 | * result to be useful, -1 otherwise. | 178 | * result to be useful, -1 otherwise. |
179 | */ | 179 | */ |
180 | static int ath_update_survey_stats(struct ath_softc *sc) | 180 | static int ath_update_survey_stats(struct ath_softc *sc) |
181 | { | 181 | { |
182 | struct ath_hw *ah = sc->sc_ah; | 182 | struct ath_hw *ah = sc->sc_ah; |
183 | struct ath_common *common = ath9k_hw_common(ah); | 183 | struct ath_common *common = ath9k_hw_common(ah); |
184 | int pos = ah->curchan - &ah->channels[0]; | 184 | int pos = ah->curchan - &ah->channels[0]; |
185 | struct survey_info *survey = &sc->survey[pos]; | 185 | struct survey_info *survey = &sc->survey[pos]; |
186 | struct ath_cycle_counters *cc = &common->cc_survey; | 186 | struct ath_cycle_counters *cc = &common->cc_survey; |
187 | unsigned int div = common->clockrate * 1000; | 187 | unsigned int div = common->clockrate * 1000; |
188 | int ret = 0; | 188 | int ret = 0; |
189 | 189 | ||
190 | if (!ah->curchan) | 190 | if (!ah->curchan) |
191 | return -1; | 191 | return -1; |
192 | 192 | ||
193 | if (ah->power_mode == ATH9K_PM_AWAKE) | 193 | if (ah->power_mode == ATH9K_PM_AWAKE) |
194 | ath_hw_cycle_counters_update(common); | 194 | ath_hw_cycle_counters_update(common); |
195 | 195 | ||
196 | if (cc->cycles > 0) { | 196 | if (cc->cycles > 0) { |
197 | survey->filled |= SURVEY_INFO_CHANNEL_TIME | | 197 | survey->filled |= SURVEY_INFO_CHANNEL_TIME | |
198 | SURVEY_INFO_CHANNEL_TIME_BUSY | | 198 | SURVEY_INFO_CHANNEL_TIME_BUSY | |
199 | SURVEY_INFO_CHANNEL_TIME_RX | | 199 | SURVEY_INFO_CHANNEL_TIME_RX | |
200 | SURVEY_INFO_CHANNEL_TIME_TX; | 200 | SURVEY_INFO_CHANNEL_TIME_TX; |
201 | survey->channel_time += cc->cycles / div; | 201 | survey->channel_time += cc->cycles / div; |
202 | survey->channel_time_busy += cc->rx_busy / div; | 202 | survey->channel_time_busy += cc->rx_busy / div; |
203 | survey->channel_time_rx += cc->rx_frame / div; | 203 | survey->channel_time_rx += cc->rx_frame / div; |
204 | survey->channel_time_tx += cc->tx_frame / div; | 204 | survey->channel_time_tx += cc->tx_frame / div; |
205 | } | 205 | } |
206 | 206 | ||
207 | if (cc->cycles < div) | 207 | if (cc->cycles < div) |
208 | return -1; | 208 | return -1; |
209 | 209 | ||
210 | if (cc->cycles > 0) | 210 | if (cc->cycles > 0) |
211 | ret = cc->rx_busy * 100 / cc->cycles; | 211 | ret = cc->rx_busy * 100 / cc->cycles; |
212 | 212 | ||
213 | memset(cc, 0, sizeof(*cc)); | 213 | memset(cc, 0, sizeof(*cc)); |
214 | 214 | ||
215 | ath_update_survey_nf(sc, pos); | 215 | ath_update_survey_nf(sc, pos); |
216 | 216 | ||
217 | return ret; | 217 | return ret; |
218 | } | 218 | } |
219 | 219 | ||
220 | static void __ath_cancel_work(struct ath_softc *sc) | 220 | static void __ath_cancel_work(struct ath_softc *sc) |
221 | { | 221 | { |
222 | cancel_work_sync(&sc->paprd_work); | 222 | cancel_work_sync(&sc->paprd_work); |
223 | cancel_work_sync(&sc->hw_check_work); | 223 | cancel_work_sync(&sc->hw_check_work); |
224 | cancel_delayed_work_sync(&sc->tx_complete_work); | 224 | cancel_delayed_work_sync(&sc->tx_complete_work); |
225 | cancel_delayed_work_sync(&sc->hw_pll_work); | 225 | cancel_delayed_work_sync(&sc->hw_pll_work); |
226 | } | 226 | } |
227 | 227 | ||
228 | static void ath_cancel_work(struct ath_softc *sc) | 228 | static void ath_cancel_work(struct ath_softc *sc) |
229 | { | 229 | { |
230 | __ath_cancel_work(sc); | 230 | __ath_cancel_work(sc); |
231 | cancel_work_sync(&sc->hw_reset_work); | 231 | cancel_work_sync(&sc->hw_reset_work); |
232 | } | 232 | } |
233 | 233 | ||
234 | static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) | 234 | static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) |
235 | { | 235 | { |
236 | struct ath_hw *ah = sc->sc_ah; | 236 | struct ath_hw *ah = sc->sc_ah; |
237 | struct ath_common *common = ath9k_hw_common(ah); | 237 | struct ath_common *common = ath9k_hw_common(ah); |
238 | bool ret; | 238 | bool ret; |
239 | 239 | ||
240 | ieee80211_stop_queues(sc->hw); | 240 | ieee80211_stop_queues(sc->hw); |
241 | 241 | ||
242 | sc->hw_busy_count = 0; | 242 | sc->hw_busy_count = 0; |
243 | del_timer_sync(&common->ani.timer); | 243 | del_timer_sync(&common->ani.timer); |
244 | 244 | ||
245 | ath9k_debug_samp_bb_mac(sc); | 245 | ath9k_debug_samp_bb_mac(sc); |
246 | ath9k_hw_disable_interrupts(ah); | 246 | ath9k_hw_disable_interrupts(ah); |
247 | 247 | ||
248 | ret = ath_drain_all_txq(sc, retry_tx); | 248 | ret = ath_drain_all_txq(sc, retry_tx); |
249 | 249 | ||
250 | if (!ath_stoprecv(sc)) | 250 | if (!ath_stoprecv(sc)) |
251 | ret = false; | 251 | ret = false; |
252 | 252 | ||
253 | if (!flush) { | 253 | if (!flush) { |
254 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | 254 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
255 | ath_rx_tasklet(sc, 1, true); | 255 | ath_rx_tasklet(sc, 1, true); |
256 | ath_rx_tasklet(sc, 1, false); | 256 | ath_rx_tasklet(sc, 1, false); |
257 | } else { | 257 | } else { |
258 | ath_flushrecv(sc); | 258 | ath_flushrecv(sc); |
259 | } | 259 | } |
260 | 260 | ||
261 | return ret; | 261 | return ret; |
262 | } | 262 | } |
263 | 263 | ||
264 | static bool ath_complete_reset(struct ath_softc *sc, bool start) | 264 | static bool ath_complete_reset(struct ath_softc *sc, bool start) |
265 | { | 265 | { |
266 | struct ath_hw *ah = sc->sc_ah; | 266 | struct ath_hw *ah = sc->sc_ah; |
267 | struct ath_common *common = ath9k_hw_common(ah); | 267 | struct ath_common *common = ath9k_hw_common(ah); |
268 | 268 | ||
269 | if (ath_startrecv(sc) != 0) { | 269 | if (ath_startrecv(sc) != 0) { |
270 | ath_err(common, "Unable to restart recv logic\n"); | 270 | ath_err(common, "Unable to restart recv logic\n"); |
271 | return false; | 271 | return false; |
272 | } | 272 | } |
273 | 273 | ||
274 | ath9k_cmn_update_txpow(ah, sc->curtxpow, | 274 | ath9k_cmn_update_txpow(ah, sc->curtxpow, |
275 | sc->config.txpowlimit, &sc->curtxpow); | 275 | sc->config.txpowlimit, &sc->curtxpow); |
276 | ath9k_hw_set_interrupts(ah); | 276 | ath9k_hw_set_interrupts(ah); |
277 | ath9k_hw_enable_interrupts(ah); | 277 | ath9k_hw_enable_interrupts(ah); |
278 | 278 | ||
279 | if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) { | 279 | if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) { |
280 | if (sc->sc_flags & SC_OP_BEACONS) | 280 | if (sc->sc_flags & SC_OP_BEACONS) |
281 | ath_set_beacon(sc); | 281 | ath_set_beacon(sc); |
282 | 282 | ||
283 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); | 283 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); |
284 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); | 284 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); |
285 | if (!common->disable_ani) | 285 | if (!common->disable_ani) |
286 | ath_start_ani(common); | 286 | ath_start_ani(common); |
287 | } | 287 | } |
288 | 288 | ||
289 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) { | 289 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) { |
290 | struct ath_hw_antcomb_conf div_ant_conf; | 290 | struct ath_hw_antcomb_conf div_ant_conf; |
291 | u8 lna_conf; | 291 | u8 lna_conf; |
292 | 292 | ||
293 | ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf); | 293 | ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf); |
294 | 294 | ||
295 | if (sc->ant_rx == 1) | 295 | if (sc->ant_rx == 1) |
296 | lna_conf = ATH_ANT_DIV_COMB_LNA1; | 296 | lna_conf = ATH_ANT_DIV_COMB_LNA1; |
297 | else | 297 | else |
298 | lna_conf = ATH_ANT_DIV_COMB_LNA2; | 298 | lna_conf = ATH_ANT_DIV_COMB_LNA2; |
299 | div_ant_conf.main_lna_conf = lna_conf; | 299 | div_ant_conf.main_lna_conf = lna_conf; |
300 | div_ant_conf.alt_lna_conf = lna_conf; | 300 | div_ant_conf.alt_lna_conf = lna_conf; |
301 | 301 | ||
302 | ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf); | 302 | ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf); |
303 | } | 303 | } |
304 | 304 | ||
305 | ieee80211_wake_queues(sc->hw); | 305 | ieee80211_wake_queues(sc->hw); |
306 | 306 | ||
307 | return true; | 307 | return true; |
308 | } | 308 | } |
309 | 309 | ||
310 | static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, | 310 | static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, |
311 | bool retry_tx) | 311 | bool retry_tx) |
312 | { | 312 | { |
313 | struct ath_hw *ah = sc->sc_ah; | 313 | struct ath_hw *ah = sc->sc_ah; |
314 | struct ath_common *common = ath9k_hw_common(ah); | 314 | struct ath_common *common = ath9k_hw_common(ah); |
315 | struct ath9k_hw_cal_data *caldata = NULL; | 315 | struct ath9k_hw_cal_data *caldata = NULL; |
316 | bool fastcc = true; | 316 | bool fastcc = true; |
317 | bool flush = false; | 317 | bool flush = false; |
318 | int r; | 318 | int r; |
319 | 319 | ||
320 | __ath_cancel_work(sc); | 320 | __ath_cancel_work(sc); |
321 | 321 | ||
322 | spin_lock_bh(&sc->sc_pcu_lock); | 322 | spin_lock_bh(&sc->sc_pcu_lock); |
323 | 323 | ||
324 | if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) { | 324 | if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) { |
325 | fastcc = false; | 325 | fastcc = false; |
326 | caldata = &sc->caldata; | 326 | caldata = &sc->caldata; |
327 | } | 327 | } |
328 | 328 | ||
329 | if (!hchan) { | 329 | if (!hchan) { |
330 | fastcc = false; | 330 | fastcc = false; |
331 | flush = true; | 331 | flush = true; |
332 | hchan = ah->curchan; | 332 | hchan = ah->curchan; |
333 | } | 333 | } |
334 | 334 | ||
335 | if (fastcc && !ath9k_hw_check_alive(ah)) | 335 | if (fastcc && !ath9k_hw_check_alive(ah)) |
336 | fastcc = false; | 336 | fastcc = false; |
337 | 337 | ||
338 | if (!ath_prepare_reset(sc, retry_tx, flush)) | 338 | if (!ath_prepare_reset(sc, retry_tx, flush)) |
339 | fastcc = false; | 339 | fastcc = false; |
340 | 340 | ||
341 | ath_dbg(common, ATH_DBG_CONFIG, | 341 | ath_dbg(common, ATH_DBG_CONFIG, |
342 | "Reset to %u MHz, HT40: %d fastcc: %d\n", | 342 | "Reset to %u MHz, HT40: %d fastcc: %d\n", |
343 | hchan->channel, !!(hchan->channelFlags & (CHANNEL_HT40MINUS | | 343 | hchan->channel, !!(hchan->channelFlags & (CHANNEL_HT40MINUS | |
344 | CHANNEL_HT40PLUS)), | 344 | CHANNEL_HT40PLUS)), |
345 | fastcc); | 345 | fastcc); |
346 | 346 | ||
347 | r = ath9k_hw_reset(ah, hchan, caldata, fastcc); | 347 | r = ath9k_hw_reset(ah, hchan, caldata, fastcc); |
348 | if (r) { | 348 | if (r) { |
349 | ath_err(common, | 349 | ath_err(common, |
350 | "Unable to reset channel, reset status %d\n", r); | 350 | "Unable to reset channel, reset status %d\n", r); |
351 | goto out; | 351 | goto out; |
352 | } | 352 | } |
353 | 353 | ||
354 | if (!ath_complete_reset(sc, true)) | 354 | if (!ath_complete_reset(sc, true)) |
355 | r = -EIO; | 355 | r = -EIO; |
356 | 356 | ||
357 | out: | 357 | out: |
358 | spin_unlock_bh(&sc->sc_pcu_lock); | 358 | spin_unlock_bh(&sc->sc_pcu_lock); |
359 | return r; | 359 | return r; |
360 | } | 360 | } |
361 | 361 | ||
362 | 362 | ||
363 | /* | 363 | /* |
364 | * Set/change channels. If the channel is really being changed, it's done | 364 | * Set/change channels. If the channel is really being changed, it's done |
365 | * by reseting the chip. To accomplish this we must first cleanup any pending | 365 | * by reseting the chip. To accomplish this we must first cleanup any pending |
366 | * DMA, then restart stuff. | 366 | * DMA, then restart stuff. |
367 | */ | 367 | */ |
368 | static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | 368 | static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, |
369 | struct ath9k_channel *hchan) | 369 | struct ath9k_channel *hchan) |
370 | { | 370 | { |
371 | int r; | 371 | int r; |
372 | 372 | ||
373 | if (sc->sc_flags & SC_OP_INVALID) | 373 | if (sc->sc_flags & SC_OP_INVALID) |
374 | return -EIO; | 374 | return -EIO; |
375 | 375 | ||
376 | ath9k_ps_wakeup(sc); | 376 | ath9k_ps_wakeup(sc); |
377 | 377 | ||
378 | r = ath_reset_internal(sc, hchan, false); | 378 | r = ath_reset_internal(sc, hchan, false); |
379 | 379 | ||
380 | ath9k_ps_restore(sc); | 380 | ath9k_ps_restore(sc); |
381 | 381 | ||
382 | return r; | 382 | return r; |
383 | } | 383 | } |
384 | 384 | ||
385 | static void ath_paprd_activate(struct ath_softc *sc) | 385 | static void ath_paprd_activate(struct ath_softc *sc) |
386 | { | 386 | { |
387 | struct ath_hw *ah = sc->sc_ah; | 387 | struct ath_hw *ah = sc->sc_ah; |
388 | struct ath9k_hw_cal_data *caldata = ah->caldata; | 388 | struct ath9k_hw_cal_data *caldata = ah->caldata; |
389 | int chain; | 389 | int chain; |
390 | 390 | ||
391 | if (!caldata || !caldata->paprd_done) | 391 | if (!caldata || !caldata->paprd_done) |
392 | return; | 392 | return; |
393 | 393 | ||
394 | ath9k_ps_wakeup(sc); | 394 | ath9k_ps_wakeup(sc); |
395 | ar9003_paprd_enable(ah, false); | 395 | ar9003_paprd_enable(ah, false); |
396 | for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { | 396 | for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { |
397 | if (!(ah->txchainmask & BIT(chain))) | 397 | if (!(ah->txchainmask & BIT(chain))) |
398 | continue; | 398 | continue; |
399 | 399 | ||
400 | ar9003_paprd_populate_single_table(ah, caldata, chain); | 400 | ar9003_paprd_populate_single_table(ah, caldata, chain); |
401 | } | 401 | } |
402 | 402 | ||
403 | ar9003_paprd_enable(ah, true); | 403 | ar9003_paprd_enable(ah, true); |
404 | ath9k_ps_restore(sc); | 404 | ath9k_ps_restore(sc); |
405 | } | 405 | } |
406 | 406 | ||
407 | static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain) | 407 | static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain) |
408 | { | 408 | { |
409 | struct ieee80211_hw *hw = sc->hw; | 409 | struct ieee80211_hw *hw = sc->hw; |
410 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 410 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
411 | struct ath_hw *ah = sc->sc_ah; | 411 | struct ath_hw *ah = sc->sc_ah; |
412 | struct ath_common *common = ath9k_hw_common(ah); | 412 | struct ath_common *common = ath9k_hw_common(ah); |
413 | struct ath_tx_control txctl; | 413 | struct ath_tx_control txctl; |
414 | int time_left; | 414 | int time_left; |
415 | 415 | ||
416 | memset(&txctl, 0, sizeof(txctl)); | 416 | memset(&txctl, 0, sizeof(txctl)); |
417 | txctl.txq = sc->tx.txq_map[WME_AC_BE]; | 417 | txctl.txq = sc->tx.txq_map[WME_AC_BE]; |
418 | 418 | ||
419 | memset(tx_info, 0, sizeof(*tx_info)); | 419 | memset(tx_info, 0, sizeof(*tx_info)); |
420 | tx_info->band = hw->conf.channel->band; | 420 | tx_info->band = hw->conf.channel->band; |
421 | tx_info->flags |= IEEE80211_TX_CTL_NO_ACK; | 421 | tx_info->flags |= IEEE80211_TX_CTL_NO_ACK; |
422 | tx_info->control.rates[0].idx = 0; | 422 | tx_info->control.rates[0].idx = 0; |
423 | tx_info->control.rates[0].count = 1; | 423 | tx_info->control.rates[0].count = 1; |
424 | tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS; | 424 | tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS; |
425 | tx_info->control.rates[1].idx = -1; | 425 | tx_info->control.rates[1].idx = -1; |
426 | 426 | ||
427 | init_completion(&sc->paprd_complete); | 427 | init_completion(&sc->paprd_complete); |
428 | txctl.paprd = BIT(chain); | 428 | txctl.paprd = BIT(chain); |
429 | 429 | ||
430 | if (ath_tx_start(hw, skb, &txctl) != 0) { | 430 | if (ath_tx_start(hw, skb, &txctl) != 0) { |
431 | ath_dbg(common, ATH_DBG_CALIBRATE, "PAPRD TX failed\n"); | 431 | ath_dbg(common, ATH_DBG_CALIBRATE, "PAPRD TX failed\n"); |
432 | dev_kfree_skb_any(skb); | 432 | dev_kfree_skb_any(skb); |
433 | return false; | 433 | return false; |
434 | } | 434 | } |
435 | 435 | ||
436 | time_left = wait_for_completion_timeout(&sc->paprd_complete, | 436 | time_left = wait_for_completion_timeout(&sc->paprd_complete, |
437 | msecs_to_jiffies(ATH_PAPRD_TIMEOUT)); | 437 | msecs_to_jiffies(ATH_PAPRD_TIMEOUT)); |
438 | 438 | ||
439 | if (!time_left) | 439 | if (!time_left) |
440 | ath_dbg(common, ATH_DBG_CALIBRATE, | 440 | ath_dbg(common, ATH_DBG_CALIBRATE, |
441 | "Timeout waiting for paprd training on TX chain %d\n", | 441 | "Timeout waiting for paprd training on TX chain %d\n", |
442 | chain); | 442 | chain); |
443 | 443 | ||
444 | return !!time_left; | 444 | return !!time_left; |
445 | } | 445 | } |
446 | 446 | ||
447 | void ath_paprd_calibrate(struct work_struct *work) | 447 | void ath_paprd_calibrate(struct work_struct *work) |
448 | { | 448 | { |
449 | struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work); | 449 | struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work); |
450 | struct ieee80211_hw *hw = sc->hw; | 450 | struct ieee80211_hw *hw = sc->hw; |
451 | struct ath_hw *ah = sc->sc_ah; | 451 | struct ath_hw *ah = sc->sc_ah; |
452 | struct ieee80211_hdr *hdr; | 452 | struct ieee80211_hdr *hdr; |
453 | struct sk_buff *skb = NULL; | 453 | struct sk_buff *skb = NULL; |
454 | struct ath9k_hw_cal_data *caldata = ah->caldata; | 454 | struct ath9k_hw_cal_data *caldata = ah->caldata; |
455 | struct ath_common *common = ath9k_hw_common(ah); | 455 | struct ath_common *common = ath9k_hw_common(ah); |
456 | int ftype; | 456 | int ftype; |
457 | int chain_ok = 0; | 457 | int chain_ok = 0; |
458 | int chain; | 458 | int chain; |
459 | int len = 1800; | 459 | int len = 1800; |
460 | 460 | ||
461 | if (!caldata) | 461 | if (!caldata) |
462 | return; | 462 | return; |
463 | 463 | ||
464 | ath9k_ps_wakeup(sc); | 464 | ath9k_ps_wakeup(sc); |
465 | 465 | ||
466 | if (ar9003_paprd_init_table(ah) < 0) | 466 | if (ar9003_paprd_init_table(ah) < 0) |
467 | goto fail_paprd; | 467 | goto fail_paprd; |
468 | 468 | ||
469 | skb = alloc_skb(len, GFP_KERNEL); | 469 | skb = alloc_skb(len, GFP_KERNEL); |
470 | if (!skb) | 470 | if (!skb) |
471 | goto fail_paprd; | 471 | goto fail_paprd; |
472 | 472 | ||
473 | skb_put(skb, len); | 473 | skb_put(skb, len); |
474 | memset(skb->data, 0, len); | 474 | memset(skb->data, 0, len); |
475 | hdr = (struct ieee80211_hdr *)skb->data; | 475 | hdr = (struct ieee80211_hdr *)skb->data; |
476 | ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC; | 476 | ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC; |
477 | hdr->frame_control = cpu_to_le16(ftype); | 477 | hdr->frame_control = cpu_to_le16(ftype); |
478 | hdr->duration_id = cpu_to_le16(10); | 478 | hdr->duration_id = cpu_to_le16(10); |
479 | memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN); | 479 | memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN); |
480 | memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); | 480 | memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); |
481 | memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); | 481 | memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); |
482 | 482 | ||
483 | for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { | 483 | for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { |
484 | if (!(ah->txchainmask & BIT(chain))) | 484 | if (!(ah->txchainmask & BIT(chain))) |
485 | continue; | 485 | continue; |
486 | 486 | ||
487 | chain_ok = 0; | 487 | chain_ok = 0; |
488 | 488 | ||
489 | ath_dbg(common, ATH_DBG_CALIBRATE, | 489 | ath_dbg(common, ATH_DBG_CALIBRATE, |
490 | "Sending PAPRD frame for thermal measurement " | 490 | "Sending PAPRD frame for thermal measurement " |
491 | "on chain %d\n", chain); | 491 | "on chain %d\n", chain); |
492 | if (!ath_paprd_send_frame(sc, skb, chain)) | 492 | if (!ath_paprd_send_frame(sc, skb, chain)) |
493 | goto fail_paprd; | 493 | goto fail_paprd; |
494 | 494 | ||
495 | ar9003_paprd_setup_gain_table(ah, chain); | 495 | ar9003_paprd_setup_gain_table(ah, chain); |
496 | 496 | ||
497 | ath_dbg(common, ATH_DBG_CALIBRATE, | 497 | ath_dbg(common, ATH_DBG_CALIBRATE, |
498 | "Sending PAPRD training frame on chain %d\n", chain); | 498 | "Sending PAPRD training frame on chain %d\n", chain); |
499 | if (!ath_paprd_send_frame(sc, skb, chain)) | 499 | if (!ath_paprd_send_frame(sc, skb, chain)) |
500 | goto fail_paprd; | 500 | goto fail_paprd; |
501 | 501 | ||
502 | if (!ar9003_paprd_is_done(ah)) { | 502 | if (!ar9003_paprd_is_done(ah)) { |
503 | ath_dbg(common, ATH_DBG_CALIBRATE, | 503 | ath_dbg(common, ATH_DBG_CALIBRATE, |
504 | "PAPRD not yet done on chain %d\n", chain); | 504 | "PAPRD not yet done on chain %d\n", chain); |
505 | break; | 505 | break; |
506 | } | 506 | } |
507 | 507 | ||
508 | if (ar9003_paprd_create_curve(ah, caldata, chain)) { | 508 | if (ar9003_paprd_create_curve(ah, caldata, chain)) { |
509 | ath_dbg(common, ATH_DBG_CALIBRATE, | 509 | ath_dbg(common, ATH_DBG_CALIBRATE, |
510 | "PAPRD create curve failed on chain %d\n", | 510 | "PAPRD create curve failed on chain %d\n", |
511 | chain); | 511 | chain); |
512 | break; | 512 | break; |
513 | } | 513 | } |
514 | 514 | ||
515 | chain_ok = 1; | 515 | chain_ok = 1; |
516 | } | 516 | } |
517 | kfree_skb(skb); | 517 | kfree_skb(skb); |
518 | 518 | ||
519 | if (chain_ok) { | 519 | if (chain_ok) { |
520 | caldata->paprd_done = true; | 520 | caldata->paprd_done = true; |
521 | ath_paprd_activate(sc); | 521 | ath_paprd_activate(sc); |
522 | } | 522 | } |
523 | 523 | ||
524 | fail_paprd: | 524 | fail_paprd: |
525 | ath9k_ps_restore(sc); | 525 | ath9k_ps_restore(sc); |
526 | } | 526 | } |
527 | 527 | ||
528 | /* | 528 | /* |
529 | * This routine performs the periodic noise floor calibration function | 529 | * This routine performs the periodic noise floor calibration function |
530 | * that is used to adjust and optimize the chip performance. This | 530 | * that is used to adjust and optimize the chip performance. This |
531 | * takes environmental changes (location, temperature) into account. | 531 | * takes environmental changes (location, temperature) into account. |
532 | * When the task is complete, it reschedules itself depending on the | 532 | * When the task is complete, it reschedules itself depending on the |
533 | * appropriate interval that was calculated. | 533 | * appropriate interval that was calculated. |
534 | */ | 534 | */ |
535 | void ath_ani_calibrate(unsigned long data) | 535 | void ath_ani_calibrate(unsigned long data) |
536 | { | 536 | { |
537 | struct ath_softc *sc = (struct ath_softc *)data; | 537 | struct ath_softc *sc = (struct ath_softc *)data; |
538 | struct ath_hw *ah = sc->sc_ah; | 538 | struct ath_hw *ah = sc->sc_ah; |
539 | struct ath_common *common = ath9k_hw_common(ah); | 539 | struct ath_common *common = ath9k_hw_common(ah); |
540 | bool longcal = false; | 540 | bool longcal = false; |
541 | bool shortcal = false; | 541 | bool shortcal = false; |
542 | bool aniflag = false; | 542 | bool aniflag = false; |
543 | unsigned int timestamp = jiffies_to_msecs(jiffies); | 543 | unsigned int timestamp = jiffies_to_msecs(jiffies); |
544 | u32 cal_interval, short_cal_interval, long_cal_interval; | 544 | u32 cal_interval, short_cal_interval, long_cal_interval; |
545 | unsigned long flags; | 545 | unsigned long flags; |
546 | 546 | ||
547 | if (ah->caldata && ah->caldata->nfcal_interference) | 547 | if (ah->caldata && ah->caldata->nfcal_interference) |
548 | long_cal_interval = ATH_LONG_CALINTERVAL_INT; | 548 | long_cal_interval = ATH_LONG_CALINTERVAL_INT; |
549 | else | 549 | else |
550 | long_cal_interval = ATH_LONG_CALINTERVAL; | 550 | long_cal_interval = ATH_LONG_CALINTERVAL; |
551 | 551 | ||
552 | short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ? | 552 | short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ? |
553 | ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL; | 553 | ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL; |
554 | 554 | ||
555 | /* Only calibrate if awake */ | 555 | /* Only calibrate if awake */ |
556 | if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) | 556 | if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) |
557 | goto set_timer; | 557 | goto set_timer; |
558 | 558 | ||
559 | ath9k_ps_wakeup(sc); | 559 | ath9k_ps_wakeup(sc); |
560 | 560 | ||
561 | /* Long calibration runs independently of short calibration. */ | 561 | /* Long calibration runs independently of short calibration. */ |
562 | if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) { | 562 | if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) { |
563 | longcal = true; | 563 | longcal = true; |
564 | ath_dbg(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies); | 564 | ath_dbg(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies); |
565 | common->ani.longcal_timer = timestamp; | 565 | common->ani.longcal_timer = timestamp; |
566 | } | 566 | } |
567 | 567 | ||
568 | /* Short calibration applies only while caldone is false */ | 568 | /* Short calibration applies only while caldone is false */ |
569 | if (!common->ani.caldone) { | 569 | if (!common->ani.caldone) { |
570 | if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) { | 570 | if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) { |
571 | shortcal = true; | 571 | shortcal = true; |
572 | ath_dbg(common, ATH_DBG_ANI, | 572 | ath_dbg(common, ATH_DBG_ANI, |
573 | "shortcal @%lu\n", jiffies); | 573 | "shortcal @%lu\n", jiffies); |
574 | common->ani.shortcal_timer = timestamp; | 574 | common->ani.shortcal_timer = timestamp; |
575 | common->ani.resetcal_timer = timestamp; | 575 | common->ani.resetcal_timer = timestamp; |
576 | } | 576 | } |
577 | } else { | 577 | } else { |
578 | if ((timestamp - common->ani.resetcal_timer) >= | 578 | if ((timestamp - common->ani.resetcal_timer) >= |
579 | ATH_RESTART_CALINTERVAL) { | 579 | ATH_RESTART_CALINTERVAL) { |
580 | common->ani.caldone = ath9k_hw_reset_calvalid(ah); | 580 | common->ani.caldone = ath9k_hw_reset_calvalid(ah); |
581 | if (common->ani.caldone) | 581 | if (common->ani.caldone) |
582 | common->ani.resetcal_timer = timestamp; | 582 | common->ani.resetcal_timer = timestamp; |
583 | } | 583 | } |
584 | } | 584 | } |
585 | 585 | ||
586 | /* Verify whether we must check ANI */ | 586 | /* Verify whether we must check ANI */ |
587 | if ((timestamp - common->ani.checkani_timer) >= | 587 | if ((timestamp - common->ani.checkani_timer) >= |
588 | ah->config.ani_poll_interval) { | 588 | ah->config.ani_poll_interval) { |
589 | aniflag = true; | 589 | aniflag = true; |
590 | common->ani.checkani_timer = timestamp; | 590 | common->ani.checkani_timer = timestamp; |
591 | } | 591 | } |
592 | 592 | ||
593 | /* Call ANI routine if necessary */ | 593 | /* Call ANI routine if necessary */ |
594 | if (aniflag) { | 594 | if (aniflag) { |
595 | spin_lock_irqsave(&common->cc_lock, flags); | 595 | spin_lock_irqsave(&common->cc_lock, flags); |
596 | ath9k_hw_ani_monitor(ah, ah->curchan); | 596 | ath9k_hw_ani_monitor(ah, ah->curchan); |
597 | ath_update_survey_stats(sc); | 597 | ath_update_survey_stats(sc); |
598 | spin_unlock_irqrestore(&common->cc_lock, flags); | 598 | spin_unlock_irqrestore(&common->cc_lock, flags); |
599 | } | 599 | } |
600 | 600 | ||
601 | /* Perform calibration if necessary */ | 601 | /* Perform calibration if necessary */ |
602 | if (longcal || shortcal) { | 602 | if (longcal || shortcal) { |
603 | common->ani.caldone = | 603 | common->ani.caldone = |
604 | ath9k_hw_calibrate(ah, ah->curchan, | 604 | ath9k_hw_calibrate(ah, ah->curchan, |
605 | ah->rxchainmask, longcal); | 605 | ah->rxchainmask, longcal); |
606 | } | 606 | } |
607 | 607 | ||
608 | ath9k_ps_restore(sc); | 608 | ath9k_ps_restore(sc); |
609 | 609 | ||
610 | set_timer: | 610 | set_timer: |
611 | /* | 611 | /* |
612 | * Set timer interval based on previous results. | 612 | * Set timer interval based on previous results. |
613 | * The interval must be the shortest necessary to satisfy ANI, | 613 | * The interval must be the shortest necessary to satisfy ANI, |
614 | * short calibration and long calibration. | 614 | * short calibration and long calibration. |
615 | */ | 615 | */ |
616 | ath9k_debug_samp_bb_mac(sc); | 616 | ath9k_debug_samp_bb_mac(sc); |
617 | cal_interval = ATH_LONG_CALINTERVAL; | 617 | cal_interval = ATH_LONG_CALINTERVAL; |
618 | if (sc->sc_ah->config.enable_ani) | 618 | if (sc->sc_ah->config.enable_ani) |
619 | cal_interval = min(cal_interval, | 619 | cal_interval = min(cal_interval, |
620 | (u32)ah->config.ani_poll_interval); | 620 | (u32)ah->config.ani_poll_interval); |
621 | if (!common->ani.caldone) | 621 | if (!common->ani.caldone) |
622 | cal_interval = min(cal_interval, (u32)short_cal_interval); | 622 | cal_interval = min(cal_interval, (u32)short_cal_interval); |
623 | 623 | ||
624 | mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); | 624 | mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); |
625 | if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) { | 625 | if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) { |
626 | if (!ah->caldata->paprd_done) | 626 | if (!ah->caldata->paprd_done) |
627 | ieee80211_queue_work(sc->hw, &sc->paprd_work); | 627 | ieee80211_queue_work(sc->hw, &sc->paprd_work); |
628 | else if (!ah->paprd_table_write_done) | 628 | else if (!ah->paprd_table_write_done) |
629 | ath_paprd_activate(sc); | 629 | ath_paprd_activate(sc); |
630 | } | 630 | } |
631 | } | 631 | } |
632 | 632 | ||
633 | static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) | 633 | static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) |
634 | { | 634 | { |
635 | struct ath_node *an; | 635 | struct ath_node *an; |
636 | an = (struct ath_node *)sta->drv_priv; | 636 | an = (struct ath_node *)sta->drv_priv; |
637 | 637 | ||
638 | #ifdef CONFIG_ATH9K_DEBUGFS | 638 | #ifdef CONFIG_ATH9K_DEBUGFS |
639 | spin_lock(&sc->nodes_lock); | 639 | spin_lock(&sc->nodes_lock); |
640 | list_add(&an->list, &sc->nodes); | 640 | list_add(&an->list, &sc->nodes); |
641 | spin_unlock(&sc->nodes_lock); | 641 | spin_unlock(&sc->nodes_lock); |
642 | an->sta = sta; | 642 | an->sta = sta; |
643 | #endif | 643 | #endif |
644 | if (sc->sc_flags & SC_OP_TXAGGR) { | 644 | if (sc->sc_flags & SC_OP_TXAGGR) { |
645 | ath_tx_node_init(sc, an); | 645 | ath_tx_node_init(sc, an); |
646 | an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + | 646 | an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + |
647 | sta->ht_cap.ampdu_factor); | 647 | sta->ht_cap.ampdu_factor); |
648 | an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); | 648 | an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); |
649 | } | 649 | } |
650 | } | 650 | } |
651 | 651 | ||
652 | static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) | 652 | static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) |
653 | { | 653 | { |
654 | struct ath_node *an = (struct ath_node *)sta->drv_priv; | 654 | struct ath_node *an = (struct ath_node *)sta->drv_priv; |
655 | 655 | ||
656 | #ifdef CONFIG_ATH9K_DEBUGFS | 656 | #ifdef CONFIG_ATH9K_DEBUGFS |
657 | spin_lock(&sc->nodes_lock); | 657 | spin_lock(&sc->nodes_lock); |
658 | list_del(&an->list); | 658 | list_del(&an->list); |
659 | spin_unlock(&sc->nodes_lock); | 659 | spin_unlock(&sc->nodes_lock); |
660 | an->sta = NULL; | 660 | an->sta = NULL; |
661 | #endif | 661 | #endif |
662 | 662 | ||
663 | if (sc->sc_flags & SC_OP_TXAGGR) | 663 | if (sc->sc_flags & SC_OP_TXAGGR) |
664 | ath_tx_node_cleanup(sc, an); | 664 | ath_tx_node_cleanup(sc, an); |
665 | } | 665 | } |
666 | 666 | ||
667 | 667 | ||
668 | void ath9k_tasklet(unsigned long data) | 668 | void ath9k_tasklet(unsigned long data) |
669 | { | 669 | { |
670 | struct ath_softc *sc = (struct ath_softc *)data; | 670 | struct ath_softc *sc = (struct ath_softc *)data; |
671 | struct ath_hw *ah = sc->sc_ah; | 671 | struct ath_hw *ah = sc->sc_ah; |
672 | struct ath_common *common = ath9k_hw_common(ah); | 672 | struct ath_common *common = ath9k_hw_common(ah); |
673 | 673 | ||
674 | u32 status = sc->intrstatus; | 674 | u32 status = sc->intrstatus; |
675 | u32 rxmask; | 675 | u32 rxmask; |
676 | 676 | ||
677 | ath9k_ps_wakeup(sc); | 677 | ath9k_ps_wakeup(sc); |
678 | spin_lock(&sc->sc_pcu_lock); | 678 | spin_lock(&sc->sc_pcu_lock); |
679 | 679 | ||
680 | if ((status & ATH9K_INT_FATAL) || | 680 | if ((status & ATH9K_INT_FATAL) || |
681 | (status & ATH9K_INT_BB_WATCHDOG)) { | 681 | (status & ATH9K_INT_BB_WATCHDOG)) { |
682 | #ifdef CONFIG_ATH9K_DEBUGFS | 682 | #ifdef CONFIG_ATH9K_DEBUGFS |
683 | enum ath_reset_type type; | 683 | enum ath_reset_type type; |
684 | 684 | ||
685 | if (status & ATH9K_INT_FATAL) | 685 | if (status & ATH9K_INT_FATAL) |
686 | type = RESET_TYPE_FATAL_INT; | 686 | type = RESET_TYPE_FATAL_INT; |
687 | else | 687 | else |
688 | type = RESET_TYPE_BB_WATCHDOG; | 688 | type = RESET_TYPE_BB_WATCHDOG; |
689 | 689 | ||
690 | RESET_STAT_INC(sc, type); | 690 | RESET_STAT_INC(sc, type); |
691 | #endif | 691 | #endif |
692 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | 692 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); |
693 | goto out; | 693 | goto out; |
694 | } | 694 | } |
695 | 695 | ||
696 | /* | 696 | /* |
697 | * Only run the baseband hang check if beacons stop working in AP or | 697 | * Only run the baseband hang check if beacons stop working in AP or |
698 | * IBSS mode, because it has a high false positive rate. For station | 698 | * IBSS mode, because it has a high false positive rate. For station |
699 | * mode it should not be necessary, since the upper layers will detect | 699 | * mode it should not be necessary, since the upper layers will detect |
700 | * this through a beacon miss automatically and the following channel | 700 | * this through a beacon miss automatically and the following channel |
701 | * change will trigger a hardware reset anyway | 701 | * change will trigger a hardware reset anyway |
702 | */ | 702 | */ |
703 | if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0 && | 703 | if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0 && |
704 | !ath9k_hw_check_alive(ah)) | 704 | !ath9k_hw_check_alive(ah)) |
705 | ieee80211_queue_work(sc->hw, &sc->hw_check_work); | 705 | ieee80211_queue_work(sc->hw, &sc->hw_check_work); |
706 | 706 | ||
707 | if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { | 707 | if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { |
708 | /* | 708 | /* |
709 | * TSF sync does not look correct; remain awake to sync with | 709 | * TSF sync does not look correct; remain awake to sync with |
710 | * the next Beacon. | 710 | * the next Beacon. |
711 | */ | 711 | */ |
712 | ath_dbg(common, ATH_DBG_PS, | 712 | ath_dbg(common, ATH_DBG_PS, |
713 | "TSFOOR - Sync with next Beacon\n"); | 713 | "TSFOOR - Sync with next Beacon\n"); |
714 | sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC; | 714 | sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC; |
715 | } | 715 | } |
716 | 716 | ||
717 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | 717 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
718 | rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL | | 718 | rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL | |
719 | ATH9K_INT_RXORN); | 719 | ATH9K_INT_RXORN); |
720 | else | 720 | else |
721 | rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); | 721 | rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); |
722 | 722 | ||
723 | if (status & rxmask) { | 723 | if (status & rxmask) { |
724 | /* Check for high priority Rx first */ | 724 | /* Check for high priority Rx first */ |
725 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && | 725 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && |
726 | (status & ATH9K_INT_RXHP)) | 726 | (status & ATH9K_INT_RXHP)) |
727 | ath_rx_tasklet(sc, 0, true); | 727 | ath_rx_tasklet(sc, 0, true); |
728 | 728 | ||
729 | ath_rx_tasklet(sc, 0, false); | 729 | ath_rx_tasklet(sc, 0, false); |
730 | } | 730 | } |
731 | 731 | ||
732 | if (status & ATH9K_INT_TX) { | 732 | if (status & ATH9K_INT_TX) { |
733 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | 733 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
734 | ath_tx_edma_tasklet(sc); | 734 | ath_tx_edma_tasklet(sc); |
735 | else | 735 | else |
736 | ath_tx_tasklet(sc); | 736 | ath_tx_tasklet(sc); |
737 | } | 737 | } |
738 | 738 | ||
739 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) | 739 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) |
740 | if (status & ATH9K_INT_GENTIMER) | 740 | if (status & ATH9K_INT_GENTIMER) |
741 | ath_gen_timer_isr(sc->sc_ah); | 741 | ath_gen_timer_isr(sc->sc_ah); |
742 | 742 | ||
743 | out: | 743 | out: |
744 | /* re-enable hardware interrupt */ | 744 | /* re-enable hardware interrupt */ |
745 | ath9k_hw_enable_interrupts(ah); | 745 | ath9k_hw_enable_interrupts(ah); |
746 | 746 | ||
747 | spin_unlock(&sc->sc_pcu_lock); | 747 | spin_unlock(&sc->sc_pcu_lock); |
748 | ath9k_ps_restore(sc); | 748 | ath9k_ps_restore(sc); |
749 | } | 749 | } |
750 | 750 | ||
751 | irqreturn_t ath_isr(int irq, void *dev) | 751 | irqreturn_t ath_isr(int irq, void *dev) |
752 | { | 752 | { |
753 | #define SCHED_INTR ( \ | 753 | #define SCHED_INTR ( \ |
754 | ATH9K_INT_FATAL | \ | 754 | ATH9K_INT_FATAL | \ |
755 | ATH9K_INT_BB_WATCHDOG | \ | 755 | ATH9K_INT_BB_WATCHDOG | \ |
756 | ATH9K_INT_RXORN | \ | 756 | ATH9K_INT_RXORN | \ |
757 | ATH9K_INT_RXEOL | \ | 757 | ATH9K_INT_RXEOL | \ |
758 | ATH9K_INT_RX | \ | 758 | ATH9K_INT_RX | \ |
759 | ATH9K_INT_RXLP | \ | 759 | ATH9K_INT_RXLP | \ |
760 | ATH9K_INT_RXHP | \ | 760 | ATH9K_INT_RXHP | \ |
761 | ATH9K_INT_TX | \ | 761 | ATH9K_INT_TX | \ |
762 | ATH9K_INT_BMISS | \ | 762 | ATH9K_INT_BMISS | \ |
763 | ATH9K_INT_CST | \ | 763 | ATH9K_INT_CST | \ |
764 | ATH9K_INT_TSFOOR | \ | 764 | ATH9K_INT_TSFOOR | \ |
765 | ATH9K_INT_GENTIMER) | 765 | ATH9K_INT_GENTIMER) |
766 | 766 | ||
767 | struct ath_softc *sc = dev; | 767 | struct ath_softc *sc = dev; |
768 | struct ath_hw *ah = sc->sc_ah; | 768 | struct ath_hw *ah = sc->sc_ah; |
769 | struct ath_common *common = ath9k_hw_common(ah); | 769 | struct ath_common *common = ath9k_hw_common(ah); |
770 | enum ath9k_int status; | 770 | enum ath9k_int status; |
771 | bool sched = false; | 771 | bool sched = false; |
772 | 772 | ||
773 | /* | 773 | /* |
774 | * The hardware is not ready/present, don't | 774 | * The hardware is not ready/present, don't |
775 | * touch anything. Note this can happen early | 775 | * touch anything. Note this can happen early |
776 | * on if the IRQ is shared. | 776 | * on if the IRQ is shared. |
777 | */ | 777 | */ |
778 | if (sc->sc_flags & SC_OP_INVALID) | 778 | if (sc->sc_flags & SC_OP_INVALID) |
779 | return IRQ_NONE; | 779 | return IRQ_NONE; |
780 | 780 | ||
781 | 781 | ||
782 | /* shared irq, not for us */ | 782 | /* shared irq, not for us */ |
783 | 783 | ||
784 | if (!ath9k_hw_intrpend(ah)) | 784 | if (!ath9k_hw_intrpend(ah)) |
785 | return IRQ_NONE; | 785 | return IRQ_NONE; |
786 | 786 | ||
787 | /* | 787 | /* |
788 | * Figure out the reason(s) for the interrupt. Note | 788 | * Figure out the reason(s) for the interrupt. Note |
789 | * that the hal returns a pseudo-ISR that may include | 789 | * that the hal returns a pseudo-ISR that may include |
790 | * bits we haven't explicitly enabled so we mask the | 790 | * bits we haven't explicitly enabled so we mask the |
791 | * value to insure we only process bits we requested. | 791 | * value to insure we only process bits we requested. |
792 | */ | 792 | */ |
793 | ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ | 793 | ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ |
794 | status &= ah->imask; /* discard unasked-for bits */ | 794 | status &= ah->imask; /* discard unasked-for bits */ |
795 | 795 | ||
796 | /* | 796 | /* |
797 | * If there are no status bits set, then this interrupt was not | 797 | * If there are no status bits set, then this interrupt was not |
798 | * for me (should have been caught above). | 798 | * for me (should have been caught above). |
799 | */ | 799 | */ |
800 | if (!status) | 800 | if (!status) |
801 | return IRQ_NONE; | 801 | return IRQ_NONE; |
802 | 802 | ||
803 | /* Cache the status */ | 803 | /* Cache the status */ |
804 | sc->intrstatus = status; | 804 | sc->intrstatus = status; |
805 | 805 | ||
806 | if (status & SCHED_INTR) | 806 | if (status & SCHED_INTR) |
807 | sched = true; | 807 | sched = true; |
808 | 808 | ||
809 | /* | 809 | /* |
810 | * If a FATAL or RXORN interrupt is received, we have to reset the | 810 | * If a FATAL or RXORN interrupt is received, we have to reset the |
811 | * chip immediately. | 811 | * chip immediately. |
812 | */ | 812 | */ |
813 | if ((status & ATH9K_INT_FATAL) || ((status & ATH9K_INT_RXORN) && | 813 | if ((status & ATH9K_INT_FATAL) || ((status & ATH9K_INT_RXORN) && |
814 | !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA))) | 814 | !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA))) |
815 | goto chip_reset; | 815 | goto chip_reset; |
816 | 816 | ||
817 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && | 817 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && |
818 | (status & ATH9K_INT_BB_WATCHDOG)) { | 818 | (status & ATH9K_INT_BB_WATCHDOG)) { |
819 | 819 | ||
820 | spin_lock(&common->cc_lock); | 820 | spin_lock(&common->cc_lock); |
821 | ath_hw_cycle_counters_update(common); | 821 | ath_hw_cycle_counters_update(common); |
822 | ar9003_hw_bb_watchdog_dbg_info(ah); | 822 | ar9003_hw_bb_watchdog_dbg_info(ah); |
823 | spin_unlock(&common->cc_lock); | 823 | spin_unlock(&common->cc_lock); |
824 | 824 | ||
825 | goto chip_reset; | 825 | goto chip_reset; |
826 | } | 826 | } |
827 | 827 | ||
828 | if (status & ATH9K_INT_SWBA) | 828 | if (status & ATH9K_INT_SWBA) |
829 | tasklet_schedule(&sc->bcon_tasklet); | 829 | tasklet_schedule(&sc->bcon_tasklet); |
830 | 830 | ||
831 | if (status & ATH9K_INT_TXURN) | 831 | if (status & ATH9K_INT_TXURN) |
832 | ath9k_hw_updatetxtriglevel(ah, true); | 832 | ath9k_hw_updatetxtriglevel(ah, true); |
833 | 833 | ||
834 | if (status & ATH9K_INT_RXEOL) { | 834 | if (status & ATH9K_INT_RXEOL) { |
835 | ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN); | 835 | ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN); |
836 | ath9k_hw_set_interrupts(ah); | 836 | ath9k_hw_set_interrupts(ah); |
837 | } | 837 | } |
838 | 838 | ||
839 | if (status & ATH9K_INT_MIB) { | 839 | if (status & ATH9K_INT_MIB) { |
840 | /* | 840 | /* |
841 | * Disable interrupts until we service the MIB | 841 | * Disable interrupts until we service the MIB |
842 | * interrupt; otherwise it will continue to | 842 | * interrupt; otherwise it will continue to |
843 | * fire. | 843 | * fire. |
844 | */ | 844 | */ |
845 | ath9k_hw_disable_interrupts(ah); | 845 | ath9k_hw_disable_interrupts(ah); |
846 | /* | 846 | /* |
847 | * Let the hal handle the event. We assume | 847 | * Let the hal handle the event. We assume |
848 | * it will clear whatever condition caused | 848 | * it will clear whatever condition caused |
849 | * the interrupt. | 849 | * the interrupt. |
850 | */ | 850 | */ |
851 | spin_lock(&common->cc_lock); | 851 | spin_lock(&common->cc_lock); |
852 | ath9k_hw_proc_mib_event(ah); | 852 | ath9k_hw_proc_mib_event(ah); |
853 | spin_unlock(&common->cc_lock); | 853 | spin_unlock(&common->cc_lock); |
854 | ath9k_hw_enable_interrupts(ah); | 854 | ath9k_hw_enable_interrupts(ah); |
855 | } | 855 | } |
856 | 856 | ||
857 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) | 857 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) |
858 | if (status & ATH9K_INT_TIM_TIMER) { | 858 | if (status & ATH9K_INT_TIM_TIMER) { |
859 | if (ATH_DBG_WARN_ON_ONCE(sc->ps_idle)) | 859 | if (ATH_DBG_WARN_ON_ONCE(sc->ps_idle)) |
860 | goto chip_reset; | 860 | goto chip_reset; |
861 | /* Clear RxAbort bit so that we can | 861 | /* Clear RxAbort bit so that we can |
862 | * receive frames */ | 862 | * receive frames */ |
863 | ath9k_setpower(sc, ATH9K_PM_AWAKE); | 863 | ath9k_setpower(sc, ATH9K_PM_AWAKE); |
864 | ath9k_hw_setrxabort(sc->sc_ah, 0); | 864 | ath9k_hw_setrxabort(sc->sc_ah, 0); |
865 | sc->ps_flags |= PS_WAIT_FOR_BEACON; | 865 | sc->ps_flags |= PS_WAIT_FOR_BEACON; |
866 | } | 866 | } |
867 | 867 | ||
868 | chip_reset: | 868 | chip_reset: |
869 | 869 | ||
870 | ath_debug_stat_interrupt(sc, status); | 870 | ath_debug_stat_interrupt(sc, status); |
871 | 871 | ||
872 | if (sched) { | 872 | if (sched) { |
873 | /* turn off every interrupt */ | 873 | /* turn off every interrupt */ |
874 | ath9k_hw_disable_interrupts(ah); | 874 | ath9k_hw_disable_interrupts(ah); |
875 | tasklet_schedule(&sc->intr_tq); | 875 | tasklet_schedule(&sc->intr_tq); |
876 | } | 876 | } |
877 | 877 | ||
878 | return IRQ_HANDLED; | 878 | return IRQ_HANDLED; |
879 | 879 | ||
880 | #undef SCHED_INTR | 880 | #undef SCHED_INTR |
881 | } | 881 | } |
882 | 882 | ||
883 | static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) | 883 | static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) |
884 | { | 884 | { |
885 | struct ath_hw *ah = sc->sc_ah; | 885 | struct ath_hw *ah = sc->sc_ah; |
886 | struct ath_common *common = ath9k_hw_common(ah); | 886 | struct ath_common *common = ath9k_hw_common(ah); |
887 | struct ieee80211_channel *channel = hw->conf.channel; | 887 | struct ieee80211_channel *channel = hw->conf.channel; |
888 | int r; | 888 | int r; |
889 | 889 | ||
890 | ath9k_ps_wakeup(sc); | 890 | ath9k_ps_wakeup(sc); |
891 | spin_lock_bh(&sc->sc_pcu_lock); | 891 | spin_lock_bh(&sc->sc_pcu_lock); |
892 | atomic_set(&ah->intr_ref_cnt, -1); | 892 | atomic_set(&ah->intr_ref_cnt, -1); |
893 | 893 | ||
894 | ath9k_hw_configpcipowersave(ah, false); | 894 | ath9k_hw_configpcipowersave(ah, false); |
895 | 895 | ||
896 | if (!ah->curchan) | 896 | if (!ah->curchan) |
897 | ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah); | 897 | ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah); |
898 | 898 | ||
899 | r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); | 899 | r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); |
900 | if (r) { | 900 | if (r) { |
901 | ath_err(common, | 901 | ath_err(common, |
902 | "Unable to reset channel (%u MHz), reset status %d\n", | 902 | "Unable to reset channel (%u MHz), reset status %d\n", |
903 | channel->center_freq, r); | 903 | channel->center_freq, r); |
904 | } | 904 | } |
905 | 905 | ||
906 | ath_complete_reset(sc, true); | 906 | ath_complete_reset(sc, true); |
907 | 907 | ||
908 | /* Enable LED */ | 908 | /* Enable LED */ |
909 | ath9k_hw_cfg_output(ah, ah->led_pin, | 909 | ath9k_hw_cfg_output(ah, ah->led_pin, |
910 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 910 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
911 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); | 911 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); |
912 | 912 | ||
913 | spin_unlock_bh(&sc->sc_pcu_lock); | 913 | spin_unlock_bh(&sc->sc_pcu_lock); |
914 | 914 | ||
915 | ath9k_ps_restore(sc); | 915 | ath9k_ps_restore(sc); |
916 | } | 916 | } |
917 | 917 | ||
918 | void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) | 918 | void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) |
919 | { | 919 | { |
920 | struct ath_hw *ah = sc->sc_ah; | 920 | struct ath_hw *ah = sc->sc_ah; |
921 | struct ieee80211_channel *channel = hw->conf.channel; | 921 | struct ieee80211_channel *channel = hw->conf.channel; |
922 | int r; | 922 | int r; |
923 | 923 | ||
924 | ath9k_ps_wakeup(sc); | 924 | ath9k_ps_wakeup(sc); |
925 | 925 | ||
926 | ath_cancel_work(sc); | 926 | ath_cancel_work(sc); |
927 | 927 | ||
928 | spin_lock_bh(&sc->sc_pcu_lock); | 928 | spin_lock_bh(&sc->sc_pcu_lock); |
929 | 929 | ||
930 | /* | 930 | /* |
931 | * Keep the LED on when the radio is disabled | 931 | * Keep the LED on when the radio is disabled |
932 | * during idle unassociated state. | 932 | * during idle unassociated state. |
933 | */ | 933 | */ |
934 | if (!sc->ps_idle) { | 934 | if (!sc->ps_idle) { |
935 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); | 935 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); |
936 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); | 936 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); |
937 | } | 937 | } |
938 | 938 | ||
939 | ath_prepare_reset(sc, false, true); | 939 | ath_prepare_reset(sc, false, true); |
940 | 940 | ||
941 | if (!ah->curchan) | 941 | if (!ah->curchan) |
942 | ah->curchan = ath9k_cmn_get_curchannel(hw, ah); | 942 | ah->curchan = ath9k_cmn_get_curchannel(hw, ah); |
943 | 943 | ||
944 | r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); | 944 | r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); |
945 | if (r) { | 945 | if (r) { |
946 | ath_err(ath9k_hw_common(sc->sc_ah), | 946 | ath_err(ath9k_hw_common(sc->sc_ah), |
947 | "Unable to reset channel (%u MHz), reset status %d\n", | 947 | "Unable to reset channel (%u MHz), reset status %d\n", |
948 | channel->center_freq, r); | 948 | channel->center_freq, r); |
949 | } | 949 | } |
950 | 950 | ||
951 | ath9k_hw_phy_disable(ah); | 951 | ath9k_hw_phy_disable(ah); |
952 | 952 | ||
953 | ath9k_hw_configpcipowersave(ah, true); | 953 | ath9k_hw_configpcipowersave(ah, true); |
954 | 954 | ||
955 | spin_unlock_bh(&sc->sc_pcu_lock); | 955 | spin_unlock_bh(&sc->sc_pcu_lock); |
956 | ath9k_ps_restore(sc); | 956 | ath9k_ps_restore(sc); |
957 | } | 957 | } |
958 | 958 | ||
959 | static int ath_reset(struct ath_softc *sc, bool retry_tx) | 959 | static int ath_reset(struct ath_softc *sc, bool retry_tx) |
960 | { | 960 | { |
961 | int r; | 961 | int r; |
962 | 962 | ||
963 | ath9k_ps_wakeup(sc); | 963 | ath9k_ps_wakeup(sc); |
964 | 964 | ||
965 | r = ath_reset_internal(sc, NULL, retry_tx); | 965 | r = ath_reset_internal(sc, NULL, retry_tx); |
966 | 966 | ||
967 | if (retry_tx) { | 967 | if (retry_tx) { |
968 | int i; | 968 | int i; |
969 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { | 969 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { |
970 | if (ATH_TXQ_SETUP(sc, i)) { | 970 | if (ATH_TXQ_SETUP(sc, i)) { |
971 | spin_lock_bh(&sc->tx.txq[i].axq_lock); | 971 | spin_lock_bh(&sc->tx.txq[i].axq_lock); |
972 | ath_txq_schedule(sc, &sc->tx.txq[i]); | 972 | ath_txq_schedule(sc, &sc->tx.txq[i]); |
973 | spin_unlock_bh(&sc->tx.txq[i].axq_lock); | 973 | spin_unlock_bh(&sc->tx.txq[i].axq_lock); |
974 | } | 974 | } |
975 | } | 975 | } |
976 | } | 976 | } |
977 | 977 | ||
978 | ath9k_ps_restore(sc); | 978 | ath9k_ps_restore(sc); |
979 | 979 | ||
980 | return r; | 980 | return r; |
981 | } | 981 | } |
982 | 982 | ||
983 | void ath_reset_work(struct work_struct *work) | 983 | void ath_reset_work(struct work_struct *work) |
984 | { | 984 | { |
985 | struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work); | 985 | struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work); |
986 | 986 | ||
987 | ath_reset(sc, true); | 987 | ath_reset(sc, true); |
988 | } | 988 | } |
989 | 989 | ||
990 | void ath_hw_check(struct work_struct *work) | 990 | void ath_hw_check(struct work_struct *work) |
991 | { | 991 | { |
992 | struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); | 992 | struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); |
993 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 993 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
994 | unsigned long flags; | 994 | unsigned long flags; |
995 | int busy; | 995 | int busy; |
996 | 996 | ||
997 | ath9k_ps_wakeup(sc); | 997 | ath9k_ps_wakeup(sc); |
998 | if (ath9k_hw_check_alive(sc->sc_ah)) | 998 | if (ath9k_hw_check_alive(sc->sc_ah)) |
999 | goto out; | 999 | goto out; |
1000 | 1000 | ||
1001 | spin_lock_irqsave(&common->cc_lock, flags); | 1001 | spin_lock_irqsave(&common->cc_lock, flags); |
1002 | busy = ath_update_survey_stats(sc); | 1002 | busy = ath_update_survey_stats(sc); |
1003 | spin_unlock_irqrestore(&common->cc_lock, flags); | 1003 | spin_unlock_irqrestore(&common->cc_lock, flags); |
1004 | 1004 | ||
1005 | ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, " | 1005 | ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, " |
1006 | "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); | 1006 | "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); |
1007 | if (busy >= 99) { | 1007 | if (busy >= 99) { |
1008 | if (++sc->hw_busy_count >= 3) { | 1008 | if (++sc->hw_busy_count >= 3) { |
1009 | RESET_STAT_INC(sc, RESET_TYPE_BB_HANG); | 1009 | RESET_STAT_INC(sc, RESET_TYPE_BB_HANG); |
1010 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | 1010 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); |
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | } else if (busy >= 0) | 1013 | } else if (busy >= 0) |
1014 | sc->hw_busy_count = 0; | 1014 | sc->hw_busy_count = 0; |
1015 | 1015 | ||
1016 | out: | 1016 | out: |
1017 | ath9k_ps_restore(sc); | 1017 | ath9k_ps_restore(sc); |
1018 | } | 1018 | } |
1019 | 1019 | ||
1020 | static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) | 1020 | static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) |
1021 | { | 1021 | { |
1022 | static int count; | 1022 | static int count; |
1023 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1023 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1024 | 1024 | ||
1025 | if (pll_sqsum >= 0x40000) { | 1025 | if (pll_sqsum >= 0x40000) { |
1026 | count++; | 1026 | count++; |
1027 | if (count == 3) { | 1027 | if (count == 3) { |
1028 | /* Rx is hung for more than 500ms. Reset it */ | 1028 | /* Rx is hung for more than 500ms. Reset it */ |
1029 | ath_dbg(common, ATH_DBG_RESET, | 1029 | ath_dbg(common, ATH_DBG_RESET, |
1030 | "Possible RX hang, resetting"); | 1030 | "Possible RX hang, resetting"); |
1031 | RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG); | 1031 | RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG); |
1032 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | 1032 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); |
1033 | count = 0; | 1033 | count = 0; |
1034 | } | 1034 | } |
1035 | } else | 1035 | } else |
1036 | count = 0; | 1036 | count = 0; |
1037 | } | 1037 | } |
1038 | 1038 | ||
1039 | void ath_hw_pll_work(struct work_struct *work) | 1039 | void ath_hw_pll_work(struct work_struct *work) |
1040 | { | 1040 | { |
1041 | struct ath_softc *sc = container_of(work, struct ath_softc, | 1041 | struct ath_softc *sc = container_of(work, struct ath_softc, |
1042 | hw_pll_work.work); | 1042 | hw_pll_work.work); |
1043 | u32 pll_sqsum; | 1043 | u32 pll_sqsum; |
1044 | 1044 | ||
1045 | if (AR_SREV_9485(sc->sc_ah)) { | 1045 | if (AR_SREV_9485(sc->sc_ah)) { |
1046 | 1046 | ||
1047 | ath9k_ps_wakeup(sc); | 1047 | ath9k_ps_wakeup(sc); |
1048 | pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); | 1048 | pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); |
1049 | ath9k_ps_restore(sc); | 1049 | ath9k_ps_restore(sc); |
1050 | 1050 | ||
1051 | ath_hw_pll_rx_hang_check(sc, pll_sqsum); | 1051 | ath_hw_pll_rx_hang_check(sc, pll_sqsum); |
1052 | 1052 | ||
1053 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); | 1053 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); |
1054 | } | 1054 | } |
1055 | } | 1055 | } |
1056 | 1056 | ||
1057 | /**********************/ | 1057 | /**********************/ |
1058 | /* mac80211 callbacks */ | 1058 | /* mac80211 callbacks */ |
1059 | /**********************/ | 1059 | /**********************/ |
1060 | 1060 | ||
1061 | static int ath9k_start(struct ieee80211_hw *hw) | 1061 | static int ath9k_start(struct ieee80211_hw *hw) |
1062 | { | 1062 | { |
1063 | struct ath_softc *sc = hw->priv; | 1063 | struct ath_softc *sc = hw->priv; |
1064 | struct ath_hw *ah = sc->sc_ah; | 1064 | struct ath_hw *ah = sc->sc_ah; |
1065 | struct ath_common *common = ath9k_hw_common(ah); | 1065 | struct ath_common *common = ath9k_hw_common(ah); |
1066 | struct ieee80211_channel *curchan = hw->conf.channel; | 1066 | struct ieee80211_channel *curchan = hw->conf.channel; |
1067 | struct ath9k_channel *init_channel; | 1067 | struct ath9k_channel *init_channel; |
1068 | int r; | 1068 | int r; |
1069 | 1069 | ||
1070 | ath_dbg(common, ATH_DBG_CONFIG, | 1070 | ath_dbg(common, ATH_DBG_CONFIG, |
1071 | "Starting driver with initial channel: %d MHz\n", | 1071 | "Starting driver with initial channel: %d MHz\n", |
1072 | curchan->center_freq); | 1072 | curchan->center_freq); |
1073 | 1073 | ||
1074 | ath9k_ps_wakeup(sc); | 1074 | ath9k_ps_wakeup(sc); |
1075 | 1075 | ||
1076 | mutex_lock(&sc->mutex); | 1076 | mutex_lock(&sc->mutex); |
1077 | 1077 | ||
1078 | /* setup initial channel */ | 1078 | /* setup initial channel */ |
1079 | sc->chan_idx = curchan->hw_value; | 1079 | sc->chan_idx = curchan->hw_value; |
1080 | 1080 | ||
1081 | init_channel = ath9k_cmn_get_curchannel(hw, ah); | 1081 | init_channel = ath9k_cmn_get_curchannel(hw, ah); |
1082 | 1082 | ||
1083 | /* Reset SERDES registers */ | 1083 | /* Reset SERDES registers */ |
1084 | ath9k_hw_configpcipowersave(ah, false); | 1084 | ath9k_hw_configpcipowersave(ah, false); |
1085 | 1085 | ||
1086 | /* | 1086 | /* |
1087 | * The basic interface to setting the hardware in a good | 1087 | * The basic interface to setting the hardware in a good |
1088 | * state is ``reset''. On return the hardware is known to | 1088 | * state is ``reset''. On return the hardware is known to |
1089 | * be powered up and with interrupts disabled. This must | 1089 | * be powered up and with interrupts disabled. This must |
1090 | * be followed by initialization of the appropriate bits | 1090 | * be followed by initialization of the appropriate bits |
1091 | * and then setup of the interrupt mask. | 1091 | * and then setup of the interrupt mask. |
1092 | */ | 1092 | */ |
1093 | spin_lock_bh(&sc->sc_pcu_lock); | 1093 | spin_lock_bh(&sc->sc_pcu_lock); |
1094 | r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); | 1094 | r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); |
1095 | if (r) { | 1095 | if (r) { |
1096 | ath_err(common, | 1096 | ath_err(common, |
1097 | "Unable to reset hardware; reset status %d (freq %u MHz)\n", | 1097 | "Unable to reset hardware; reset status %d (freq %u MHz)\n", |
1098 | r, curchan->center_freq); | 1098 | r, curchan->center_freq); |
1099 | spin_unlock_bh(&sc->sc_pcu_lock); | 1099 | spin_unlock_bh(&sc->sc_pcu_lock); |
1100 | goto mutex_unlock; | 1100 | goto mutex_unlock; |
1101 | } | 1101 | } |
1102 | 1102 | ||
1103 | /* Setup our intr mask. */ | 1103 | /* Setup our intr mask. */ |
1104 | ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | | 1104 | ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | |
1105 | ATH9K_INT_RXORN | ATH9K_INT_FATAL | | 1105 | ATH9K_INT_RXORN | ATH9K_INT_FATAL | |
1106 | ATH9K_INT_GLOBAL; | 1106 | ATH9K_INT_GLOBAL; |
1107 | 1107 | ||
1108 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | 1108 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
1109 | ah->imask |= ATH9K_INT_RXHP | | 1109 | ah->imask |= ATH9K_INT_RXHP | |
1110 | ATH9K_INT_RXLP | | 1110 | ATH9K_INT_RXLP | |
1111 | ATH9K_INT_BB_WATCHDOG; | 1111 | ATH9K_INT_BB_WATCHDOG; |
1112 | else | 1112 | else |
1113 | ah->imask |= ATH9K_INT_RX; | 1113 | ah->imask |= ATH9K_INT_RX; |
1114 | 1114 | ||
1115 | ah->imask |= ATH9K_INT_GTT; | 1115 | ah->imask |= ATH9K_INT_GTT; |
1116 | 1116 | ||
1117 | if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) | 1117 | if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) |
1118 | ah->imask |= ATH9K_INT_CST; | 1118 | ah->imask |= ATH9K_INT_CST; |
1119 | 1119 | ||
1120 | sc->sc_flags &= ~SC_OP_INVALID; | 1120 | sc->sc_flags &= ~SC_OP_INVALID; |
1121 | sc->sc_ah->is_monitoring = false; | 1121 | sc->sc_ah->is_monitoring = false; |
1122 | 1122 | ||
1123 | /* Disable BMISS interrupt when we're not associated */ | 1123 | /* Disable BMISS interrupt when we're not associated */ |
1124 | ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); | 1124 | ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); |
1125 | 1125 | ||
1126 | if (!ath_complete_reset(sc, false)) { | 1126 | if (!ath_complete_reset(sc, false)) { |
1127 | r = -EIO; | 1127 | r = -EIO; |
1128 | spin_unlock_bh(&sc->sc_pcu_lock); | 1128 | spin_unlock_bh(&sc->sc_pcu_lock); |
1129 | goto mutex_unlock; | 1129 | goto mutex_unlock; |
1130 | } | 1130 | } |
1131 | 1131 | ||
1132 | spin_unlock_bh(&sc->sc_pcu_lock); | 1132 | spin_unlock_bh(&sc->sc_pcu_lock); |
1133 | 1133 | ||
1134 | if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) && | 1134 | if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) && |
1135 | !ah->btcoex_hw.enabled) { | 1135 | !ah->btcoex_hw.enabled) { |
1136 | ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, | 1136 | ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, |
1137 | AR_STOMP_LOW_WLAN_WGHT); | 1137 | AR_STOMP_LOW_WLAN_WGHT); |
1138 | ath9k_hw_btcoex_enable(ah); | 1138 | ath9k_hw_btcoex_enable(ah); |
1139 | 1139 | ||
1140 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) | 1140 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) |
1141 | ath9k_btcoex_timer_resume(sc); | 1141 | ath9k_btcoex_timer_resume(sc); |
1142 | } | 1142 | } |
1143 | 1143 | ||
1144 | if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en) | 1144 | if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en) |
1145 | common->bus_ops->extn_synch_en(common); | 1145 | common->bus_ops->extn_synch_en(common); |
1146 | 1146 | ||
1147 | mutex_unlock: | 1147 | mutex_unlock: |
1148 | mutex_unlock(&sc->mutex); | 1148 | mutex_unlock(&sc->mutex); |
1149 | 1149 | ||
1150 | ath9k_ps_restore(sc); | 1150 | ath9k_ps_restore(sc); |
1151 | 1151 | ||
1152 | return r; | 1152 | return r; |
1153 | } | 1153 | } |
1154 | 1154 | ||
1155 | static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | 1155 | static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) |
1156 | { | 1156 | { |
1157 | struct ath_softc *sc = hw->priv; | 1157 | struct ath_softc *sc = hw->priv; |
1158 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1158 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1159 | struct ath_tx_control txctl; | 1159 | struct ath_tx_control txctl; |
1160 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 1160 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
1161 | 1161 | ||
1162 | if (sc->ps_enabled) { | 1162 | if (sc->ps_enabled) { |
1163 | /* | 1163 | /* |
1164 | * mac80211 does not set PM field for normal data frames, so we | 1164 | * mac80211 does not set PM field for normal data frames, so we |
1165 | * need to update that based on the current PS mode. | 1165 | * need to update that based on the current PS mode. |
1166 | */ | 1166 | */ |
1167 | if (ieee80211_is_data(hdr->frame_control) && | 1167 | if (ieee80211_is_data(hdr->frame_control) && |
1168 | !ieee80211_is_nullfunc(hdr->frame_control) && | 1168 | !ieee80211_is_nullfunc(hdr->frame_control) && |
1169 | !ieee80211_has_pm(hdr->frame_control)) { | 1169 | !ieee80211_has_pm(hdr->frame_control)) { |
1170 | ath_dbg(common, ATH_DBG_PS, | 1170 | ath_dbg(common, ATH_DBG_PS, |
1171 | "Add PM=1 for a TX frame while in PS mode\n"); | 1171 | "Add PM=1 for a TX frame while in PS mode\n"); |
1172 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | 1172 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); |
1173 | } | 1173 | } |
1174 | } | 1174 | } |
1175 | 1175 | ||
1176 | if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) { | 1176 | if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) { |
1177 | /* | 1177 | /* |
1178 | * We are using PS-Poll and mac80211 can request TX while in | 1178 | * We are using PS-Poll and mac80211 can request TX while in |
1179 | * power save mode. Need to wake up hardware for the TX to be | 1179 | * power save mode. Need to wake up hardware for the TX to be |
1180 | * completed and if needed, also for RX of buffered frames. | 1180 | * completed and if needed, also for RX of buffered frames. |
1181 | */ | 1181 | */ |
1182 | ath9k_ps_wakeup(sc); | 1182 | ath9k_ps_wakeup(sc); |
1183 | if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) | 1183 | if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) |
1184 | ath9k_hw_setrxabort(sc->sc_ah, 0); | 1184 | ath9k_hw_setrxabort(sc->sc_ah, 0); |
1185 | if (ieee80211_is_pspoll(hdr->frame_control)) { | 1185 | if (ieee80211_is_pspoll(hdr->frame_control)) { |
1186 | ath_dbg(common, ATH_DBG_PS, | 1186 | ath_dbg(common, ATH_DBG_PS, |
1187 | "Sending PS-Poll to pick a buffered frame\n"); | 1187 | "Sending PS-Poll to pick a buffered frame\n"); |
1188 | sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA; | 1188 | sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA; |
1189 | } else { | 1189 | } else { |
1190 | ath_dbg(common, ATH_DBG_PS, | 1190 | ath_dbg(common, ATH_DBG_PS, |
1191 | "Wake up to complete TX\n"); | 1191 | "Wake up to complete TX\n"); |
1192 | sc->ps_flags |= PS_WAIT_FOR_TX_ACK; | 1192 | sc->ps_flags |= PS_WAIT_FOR_TX_ACK; |
1193 | } | 1193 | } |
1194 | /* | 1194 | /* |
1195 | * The actual restore operation will happen only after | 1195 | * The actual restore operation will happen only after |
1196 | * the sc_flags bit is cleared. We are just dropping | 1196 | * the sc_flags bit is cleared. We are just dropping |
1197 | * the ps_usecount here. | 1197 | * the ps_usecount here. |
1198 | */ | 1198 | */ |
1199 | ath9k_ps_restore(sc); | 1199 | ath9k_ps_restore(sc); |
1200 | } | 1200 | } |
1201 | 1201 | ||
1202 | memset(&txctl, 0, sizeof(struct ath_tx_control)); | 1202 | memset(&txctl, 0, sizeof(struct ath_tx_control)); |
1203 | txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)]; | 1203 | txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)]; |
1204 | 1204 | ||
1205 | ath_dbg(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); | 1205 | ath_dbg(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); |
1206 | 1206 | ||
1207 | if (ath_tx_start(hw, skb, &txctl) != 0) { | 1207 | if (ath_tx_start(hw, skb, &txctl) != 0) { |
1208 | ath_dbg(common, ATH_DBG_XMIT, "TX failed\n"); | 1208 | ath_dbg(common, ATH_DBG_XMIT, "TX failed\n"); |
1209 | goto exit; | 1209 | goto exit; |
1210 | } | 1210 | } |
1211 | 1211 | ||
1212 | return; | 1212 | return; |
1213 | exit: | 1213 | exit: |
1214 | dev_kfree_skb_any(skb); | 1214 | dev_kfree_skb_any(skb); |
1215 | } | 1215 | } |
1216 | 1216 | ||
1217 | static void ath9k_stop(struct ieee80211_hw *hw) | 1217 | static void ath9k_stop(struct ieee80211_hw *hw) |
1218 | { | 1218 | { |
1219 | struct ath_softc *sc = hw->priv; | 1219 | struct ath_softc *sc = hw->priv; |
1220 | struct ath_hw *ah = sc->sc_ah; | 1220 | struct ath_hw *ah = sc->sc_ah; |
1221 | struct ath_common *common = ath9k_hw_common(ah); | 1221 | struct ath_common *common = ath9k_hw_common(ah); |
1222 | 1222 | ||
1223 | mutex_lock(&sc->mutex); | 1223 | mutex_lock(&sc->mutex); |
1224 | 1224 | ||
1225 | ath_cancel_work(sc); | 1225 | ath_cancel_work(sc); |
1226 | 1226 | ||
1227 | if (sc->sc_flags & SC_OP_INVALID) { | 1227 | if (sc->sc_flags & SC_OP_INVALID) { |
1228 | ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); | 1228 | ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); |
1229 | mutex_unlock(&sc->mutex); | 1229 | mutex_unlock(&sc->mutex); |
1230 | return; | 1230 | return; |
1231 | } | 1231 | } |
1232 | 1232 | ||
1233 | /* Ensure HW is awake when we try to shut it down. */ | 1233 | /* Ensure HW is awake when we try to shut it down. */ |
1234 | ath9k_ps_wakeup(sc); | 1234 | ath9k_ps_wakeup(sc); |
1235 | 1235 | ||
1236 | if (ah->btcoex_hw.enabled) { | 1236 | if (ah->btcoex_hw.enabled) { |
1237 | ath9k_hw_btcoex_disable(ah); | 1237 | ath9k_hw_btcoex_disable(ah); |
1238 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) | 1238 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) |
1239 | ath9k_btcoex_timer_pause(sc); | 1239 | ath9k_btcoex_timer_pause(sc); |
1240 | } | 1240 | } |
1241 | 1241 | ||
1242 | spin_lock_bh(&sc->sc_pcu_lock); | 1242 | spin_lock_bh(&sc->sc_pcu_lock); |
1243 | 1243 | ||
1244 | /* prevent tasklets to enable interrupts once we disable them */ | 1244 | /* prevent tasklets to enable interrupts once we disable them */ |
1245 | ah->imask &= ~ATH9K_INT_GLOBAL; | 1245 | ah->imask &= ~ATH9K_INT_GLOBAL; |
1246 | 1246 | ||
1247 | /* make sure h/w will not generate any interrupt | 1247 | /* make sure h/w will not generate any interrupt |
1248 | * before setting the invalid flag. */ | 1248 | * before setting the invalid flag. */ |
1249 | ath9k_hw_disable_interrupts(ah); | 1249 | ath9k_hw_disable_interrupts(ah); |
1250 | 1250 | ||
1251 | if (!(sc->sc_flags & SC_OP_INVALID)) { | 1251 | if (!(sc->sc_flags & SC_OP_INVALID)) { |
1252 | ath_drain_all_txq(sc, false); | 1252 | ath_drain_all_txq(sc, false); |
1253 | ath_stoprecv(sc); | 1253 | ath_stoprecv(sc); |
1254 | ath9k_hw_phy_disable(ah); | 1254 | ath9k_hw_phy_disable(ah); |
1255 | } else | 1255 | } else |
1256 | sc->rx.rxlink = NULL; | 1256 | sc->rx.rxlink = NULL; |
1257 | 1257 | ||
1258 | if (sc->rx.frag) { | 1258 | if (sc->rx.frag) { |
1259 | dev_kfree_skb_any(sc->rx.frag); | 1259 | dev_kfree_skb_any(sc->rx.frag); |
1260 | sc->rx.frag = NULL; | 1260 | sc->rx.frag = NULL; |
1261 | } | 1261 | } |
1262 | 1262 | ||
1263 | /* disable HAL and put h/w to sleep */ | 1263 | /* disable HAL and put h/w to sleep */ |
1264 | ath9k_hw_disable(ah); | 1264 | ath9k_hw_disable(ah); |
1265 | 1265 | ||
1266 | spin_unlock_bh(&sc->sc_pcu_lock); | 1266 | spin_unlock_bh(&sc->sc_pcu_lock); |
1267 | 1267 | ||
1268 | /* we can now sync irq and kill any running tasklets, since we already | 1268 | /* we can now sync irq and kill any running tasklets, since we already |
1269 | * disabled interrupts and not holding a spin lock */ | 1269 | * disabled interrupts and not holding a spin lock */ |
1270 | synchronize_irq(sc->irq); | 1270 | synchronize_irq(sc->irq); |
1271 | tasklet_kill(&sc->intr_tq); | 1271 | tasklet_kill(&sc->intr_tq); |
1272 | tasklet_kill(&sc->bcon_tasklet); | 1272 | tasklet_kill(&sc->bcon_tasklet); |
1273 | 1273 | ||
1274 | ath9k_ps_restore(sc); | 1274 | ath9k_ps_restore(sc); |
1275 | 1275 | ||
1276 | sc->ps_idle = true; | 1276 | sc->ps_idle = true; |
1277 | ath_radio_disable(sc, hw); | 1277 | ath_radio_disable(sc, hw); |
1278 | 1278 | ||
1279 | sc->sc_flags |= SC_OP_INVALID; | 1279 | sc->sc_flags |= SC_OP_INVALID; |
1280 | 1280 | ||
1281 | mutex_unlock(&sc->mutex); | 1281 | mutex_unlock(&sc->mutex); |
1282 | 1282 | ||
1283 | ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n"); | 1283 | ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n"); |
1284 | } | 1284 | } |
1285 | 1285 | ||
1286 | bool ath9k_uses_beacons(int type) | 1286 | bool ath9k_uses_beacons(int type) |
1287 | { | 1287 | { |
1288 | switch (type) { | 1288 | switch (type) { |
1289 | case NL80211_IFTYPE_AP: | 1289 | case NL80211_IFTYPE_AP: |
1290 | case NL80211_IFTYPE_ADHOC: | 1290 | case NL80211_IFTYPE_ADHOC: |
1291 | case NL80211_IFTYPE_MESH_POINT: | 1291 | case NL80211_IFTYPE_MESH_POINT: |
1292 | return true; | 1292 | return true; |
1293 | default: | 1293 | default: |
1294 | return false; | 1294 | return false; |
1295 | } | 1295 | } |
1296 | } | 1296 | } |
1297 | 1297 | ||
1298 | static void ath9k_reclaim_beacon(struct ath_softc *sc, | 1298 | static void ath9k_reclaim_beacon(struct ath_softc *sc, |
1299 | struct ieee80211_vif *vif) | 1299 | struct ieee80211_vif *vif) |
1300 | { | 1300 | { |
1301 | struct ath_vif *avp = (void *)vif->drv_priv; | 1301 | struct ath_vif *avp = (void *)vif->drv_priv; |
1302 | 1302 | ||
1303 | ath9k_set_beaconing_status(sc, false); | 1303 | ath9k_set_beaconing_status(sc, false); |
1304 | ath_beacon_return(sc, avp); | 1304 | ath_beacon_return(sc, avp); |
1305 | ath9k_set_beaconing_status(sc, true); | 1305 | ath9k_set_beaconing_status(sc, true); |
1306 | sc->sc_flags &= ~SC_OP_BEACONS; | 1306 | sc->sc_flags &= ~SC_OP_BEACONS; |
1307 | } | 1307 | } |
1308 | 1308 | ||
1309 | static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | 1309 | static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) |
1310 | { | 1310 | { |
1311 | struct ath9k_vif_iter_data *iter_data = data; | 1311 | struct ath9k_vif_iter_data *iter_data = data; |
1312 | int i; | 1312 | int i; |
1313 | 1313 | ||
1314 | if (iter_data->hw_macaddr) | 1314 | if (iter_data->hw_macaddr) |
1315 | for (i = 0; i < ETH_ALEN; i++) | 1315 | for (i = 0; i < ETH_ALEN; i++) |
1316 | iter_data->mask[i] &= | 1316 | iter_data->mask[i] &= |
1317 | ~(iter_data->hw_macaddr[i] ^ mac[i]); | 1317 | ~(iter_data->hw_macaddr[i] ^ mac[i]); |
1318 | 1318 | ||
1319 | switch (vif->type) { | 1319 | switch (vif->type) { |
1320 | case NL80211_IFTYPE_AP: | 1320 | case NL80211_IFTYPE_AP: |
1321 | iter_data->naps++; | 1321 | iter_data->naps++; |
1322 | break; | 1322 | break; |
1323 | case NL80211_IFTYPE_STATION: | 1323 | case NL80211_IFTYPE_STATION: |
1324 | iter_data->nstations++; | 1324 | iter_data->nstations++; |
1325 | break; | 1325 | break; |
1326 | case NL80211_IFTYPE_ADHOC: | 1326 | case NL80211_IFTYPE_ADHOC: |
1327 | iter_data->nadhocs++; | 1327 | iter_data->nadhocs++; |
1328 | break; | 1328 | break; |
1329 | case NL80211_IFTYPE_MESH_POINT: | 1329 | case NL80211_IFTYPE_MESH_POINT: |
1330 | iter_data->nmeshes++; | 1330 | iter_data->nmeshes++; |
1331 | break; | 1331 | break; |
1332 | case NL80211_IFTYPE_WDS: | 1332 | case NL80211_IFTYPE_WDS: |
1333 | iter_data->nwds++; | 1333 | iter_data->nwds++; |
1334 | break; | 1334 | break; |
1335 | default: | 1335 | default: |
1336 | iter_data->nothers++; | 1336 | iter_data->nothers++; |
1337 | break; | 1337 | break; |
1338 | } | 1338 | } |
1339 | } | 1339 | } |
1340 | 1340 | ||
1341 | /* Called with sc->mutex held. */ | 1341 | /* Called with sc->mutex held. */ |
1342 | void ath9k_calculate_iter_data(struct ieee80211_hw *hw, | 1342 | void ath9k_calculate_iter_data(struct ieee80211_hw *hw, |
1343 | struct ieee80211_vif *vif, | 1343 | struct ieee80211_vif *vif, |
1344 | struct ath9k_vif_iter_data *iter_data) | 1344 | struct ath9k_vif_iter_data *iter_data) |
1345 | { | 1345 | { |
1346 | struct ath_softc *sc = hw->priv; | 1346 | struct ath_softc *sc = hw->priv; |
1347 | struct ath_hw *ah = sc->sc_ah; | 1347 | struct ath_hw *ah = sc->sc_ah; |
1348 | struct ath_common *common = ath9k_hw_common(ah); | 1348 | struct ath_common *common = ath9k_hw_common(ah); |
1349 | 1349 | ||
1350 | /* | 1350 | /* |
1351 | * Use the hardware MAC address as reference, the hardware uses it | 1351 | * Use the hardware MAC address as reference, the hardware uses it |
1352 | * together with the BSSID mask when matching addresses. | 1352 | * together with the BSSID mask when matching addresses. |
1353 | */ | 1353 | */ |
1354 | memset(iter_data, 0, sizeof(*iter_data)); | 1354 | memset(iter_data, 0, sizeof(*iter_data)); |
1355 | iter_data->hw_macaddr = common->macaddr; | 1355 | iter_data->hw_macaddr = common->macaddr; |
1356 | memset(&iter_data->mask, 0xff, ETH_ALEN); | 1356 | memset(&iter_data->mask, 0xff, ETH_ALEN); |
1357 | 1357 | ||
1358 | if (vif) | 1358 | if (vif) |
1359 | ath9k_vif_iter(iter_data, vif->addr, vif); | 1359 | ath9k_vif_iter(iter_data, vif->addr, vif); |
1360 | 1360 | ||
1361 | /* Get list of all active MAC addresses */ | 1361 | /* Get list of all active MAC addresses */ |
1362 | ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, | 1362 | ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, |
1363 | iter_data); | 1363 | iter_data); |
1364 | } | 1364 | } |
1365 | 1365 | ||
1366 | /* Called with sc->mutex held. */ | 1366 | /* Called with sc->mutex held. */ |
1367 | static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, | 1367 | static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, |
1368 | struct ieee80211_vif *vif) | 1368 | struct ieee80211_vif *vif) |
1369 | { | 1369 | { |
1370 | struct ath_softc *sc = hw->priv; | 1370 | struct ath_softc *sc = hw->priv; |
1371 | struct ath_hw *ah = sc->sc_ah; | 1371 | struct ath_hw *ah = sc->sc_ah; |
1372 | struct ath_common *common = ath9k_hw_common(ah); | 1372 | struct ath_common *common = ath9k_hw_common(ah); |
1373 | struct ath9k_vif_iter_data iter_data; | 1373 | struct ath9k_vif_iter_data iter_data; |
1374 | 1374 | ||
1375 | ath9k_calculate_iter_data(hw, vif, &iter_data); | 1375 | ath9k_calculate_iter_data(hw, vif, &iter_data); |
1376 | 1376 | ||
1377 | /* Set BSSID mask. */ | 1377 | /* Set BSSID mask. */ |
1378 | memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); | 1378 | memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); |
1379 | ath_hw_setbssidmask(common); | 1379 | ath_hw_setbssidmask(common); |
1380 | 1380 | ||
1381 | /* Set op-mode & TSF */ | 1381 | /* Set op-mode & TSF */ |
1382 | if (iter_data.naps > 0) { | 1382 | if (iter_data.naps > 0) { |
1383 | ath9k_hw_set_tsfadjust(ah, 1); | 1383 | ath9k_hw_set_tsfadjust(ah, 1); |
1384 | sc->sc_flags |= SC_OP_TSF_RESET; | 1384 | sc->sc_flags |= SC_OP_TSF_RESET; |
1385 | ah->opmode = NL80211_IFTYPE_AP; | 1385 | ah->opmode = NL80211_IFTYPE_AP; |
1386 | } else { | 1386 | } else { |
1387 | ath9k_hw_set_tsfadjust(ah, 0); | 1387 | ath9k_hw_set_tsfadjust(ah, 0); |
1388 | sc->sc_flags &= ~SC_OP_TSF_RESET; | 1388 | sc->sc_flags &= ~SC_OP_TSF_RESET; |
1389 | 1389 | ||
1390 | if (iter_data.nmeshes) | 1390 | if (iter_data.nmeshes) |
1391 | ah->opmode = NL80211_IFTYPE_MESH_POINT; | 1391 | ah->opmode = NL80211_IFTYPE_MESH_POINT; |
1392 | else if (iter_data.nwds) | 1392 | else if (iter_data.nwds) |
1393 | ah->opmode = NL80211_IFTYPE_AP; | 1393 | ah->opmode = NL80211_IFTYPE_AP; |
1394 | else if (iter_data.nadhocs) | 1394 | else if (iter_data.nadhocs) |
1395 | ah->opmode = NL80211_IFTYPE_ADHOC; | 1395 | ah->opmode = NL80211_IFTYPE_ADHOC; |
1396 | else | 1396 | else |
1397 | ah->opmode = NL80211_IFTYPE_STATION; | 1397 | ah->opmode = NL80211_IFTYPE_STATION; |
1398 | } | 1398 | } |
1399 | 1399 | ||
1400 | /* | 1400 | /* |
1401 | * Enable MIB interrupts when there are hardware phy counters. | 1401 | * Enable MIB interrupts when there are hardware phy counters. |
1402 | */ | 1402 | */ |
1403 | if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) { | 1403 | if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) { |
1404 | if (ah->config.enable_ani) | 1404 | if (ah->config.enable_ani) |
1405 | ah->imask |= ATH9K_INT_MIB; | 1405 | ah->imask |= ATH9K_INT_MIB; |
1406 | ah->imask |= ATH9K_INT_TSFOOR; | 1406 | ah->imask |= ATH9K_INT_TSFOOR; |
1407 | } else { | 1407 | } else { |
1408 | ah->imask &= ~ATH9K_INT_MIB; | 1408 | ah->imask &= ~ATH9K_INT_MIB; |
1409 | ah->imask &= ~ATH9K_INT_TSFOOR; | 1409 | ah->imask &= ~ATH9K_INT_TSFOOR; |
1410 | } | 1410 | } |
1411 | 1411 | ||
1412 | ath9k_hw_set_interrupts(ah); | 1412 | ath9k_hw_set_interrupts(ah); |
1413 | 1413 | ||
1414 | /* Set up ANI */ | 1414 | /* Set up ANI */ |
1415 | if (iter_data.naps > 0) { | 1415 | if (iter_data.naps > 0) { |
1416 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; | 1416 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; |
1417 | 1417 | ||
1418 | if (!common->disable_ani) { | 1418 | if (!common->disable_ani) { |
1419 | sc->sc_flags |= SC_OP_ANI_RUN; | 1419 | sc->sc_flags |= SC_OP_ANI_RUN; |
1420 | ath_start_ani(common); | 1420 | ath_start_ani(common); |
1421 | } | 1421 | } |
1422 | 1422 | ||
1423 | } else { | 1423 | } else { |
1424 | sc->sc_flags &= ~SC_OP_ANI_RUN; | 1424 | sc->sc_flags &= ~SC_OP_ANI_RUN; |
1425 | del_timer_sync(&common->ani.timer); | 1425 | del_timer_sync(&common->ani.timer); |
1426 | } | 1426 | } |
1427 | } | 1427 | } |
1428 | 1428 | ||
1429 | /* Called with sc->mutex held, vif counts set up properly. */ | 1429 | /* Called with sc->mutex held, vif counts set up properly. */ |
1430 | static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw, | 1430 | static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw, |
1431 | struct ieee80211_vif *vif) | 1431 | struct ieee80211_vif *vif) |
1432 | { | 1432 | { |
1433 | struct ath_softc *sc = hw->priv; | 1433 | struct ath_softc *sc = hw->priv; |
1434 | 1434 | ||
1435 | ath9k_calculate_summary_state(hw, vif); | 1435 | ath9k_calculate_summary_state(hw, vif); |
1436 | 1436 | ||
1437 | if (ath9k_uses_beacons(vif->type)) { | 1437 | if (ath9k_uses_beacons(vif->type)) { |
1438 | int error; | 1438 | int error; |
1439 | /* This may fail because upper levels do not have beacons | 1439 | /* This may fail because upper levels do not have beacons |
1440 | * properly configured yet. That's OK, we assume it | 1440 | * properly configured yet. That's OK, we assume it |
1441 | * will be properly configured and then we will be notified | 1441 | * will be properly configured and then we will be notified |
1442 | * in the info_changed method and set up beacons properly | 1442 | * in the info_changed method and set up beacons properly |
1443 | * there. | 1443 | * there. |
1444 | */ | 1444 | */ |
1445 | ath9k_set_beaconing_status(sc, false); | 1445 | ath9k_set_beaconing_status(sc, false); |
1446 | error = ath_beacon_alloc(sc, vif); | 1446 | error = ath_beacon_alloc(sc, vif); |
1447 | if (!error) | 1447 | if (!error) |
1448 | ath_beacon_config(sc, vif); | 1448 | ath_beacon_config(sc, vif); |
1449 | ath9k_set_beaconing_status(sc, true); | 1449 | ath9k_set_beaconing_status(sc, true); |
1450 | } | 1450 | } |
1451 | } | 1451 | } |
1452 | 1452 | ||
1453 | 1453 | ||
1454 | static int ath9k_add_interface(struct ieee80211_hw *hw, | 1454 | static int ath9k_add_interface(struct ieee80211_hw *hw, |
1455 | struct ieee80211_vif *vif) | 1455 | struct ieee80211_vif *vif) |
1456 | { | 1456 | { |
1457 | struct ath_softc *sc = hw->priv; | 1457 | struct ath_softc *sc = hw->priv; |
1458 | struct ath_hw *ah = sc->sc_ah; | 1458 | struct ath_hw *ah = sc->sc_ah; |
1459 | struct ath_common *common = ath9k_hw_common(ah); | 1459 | struct ath_common *common = ath9k_hw_common(ah); |
1460 | int ret = 0; | 1460 | int ret = 0; |
1461 | 1461 | ||
1462 | ath9k_ps_wakeup(sc); | 1462 | ath9k_ps_wakeup(sc); |
1463 | mutex_lock(&sc->mutex); | 1463 | mutex_lock(&sc->mutex); |
1464 | 1464 | ||
1465 | switch (vif->type) { | 1465 | switch (vif->type) { |
1466 | case NL80211_IFTYPE_STATION: | 1466 | case NL80211_IFTYPE_STATION: |
1467 | case NL80211_IFTYPE_WDS: | 1467 | case NL80211_IFTYPE_WDS: |
1468 | case NL80211_IFTYPE_ADHOC: | 1468 | case NL80211_IFTYPE_ADHOC: |
1469 | case NL80211_IFTYPE_AP: | 1469 | case NL80211_IFTYPE_AP: |
1470 | case NL80211_IFTYPE_MESH_POINT: | 1470 | case NL80211_IFTYPE_MESH_POINT: |
1471 | break; | 1471 | break; |
1472 | default: | 1472 | default: |
1473 | ath_err(common, "Interface type %d not yet supported\n", | 1473 | ath_err(common, "Interface type %d not yet supported\n", |
1474 | vif->type); | 1474 | vif->type); |
1475 | ret = -EOPNOTSUPP; | 1475 | ret = -EOPNOTSUPP; |
1476 | goto out; | 1476 | goto out; |
1477 | } | 1477 | } |
1478 | 1478 | ||
1479 | if (ath9k_uses_beacons(vif->type)) { | 1479 | if (ath9k_uses_beacons(vif->type)) { |
1480 | if (sc->nbcnvifs >= ATH_BCBUF) { | 1480 | if (sc->nbcnvifs >= ATH_BCBUF) { |
1481 | ath_err(common, "Not enough beacon buffers when adding" | 1481 | ath_err(common, "Not enough beacon buffers when adding" |
1482 | " new interface of type: %i\n", | 1482 | " new interface of type: %i\n", |
1483 | vif->type); | 1483 | vif->type); |
1484 | ret = -ENOBUFS; | 1484 | ret = -ENOBUFS; |
1485 | goto out; | 1485 | goto out; |
1486 | } | 1486 | } |
1487 | } | 1487 | } |
1488 | 1488 | ||
1489 | if ((ah->opmode == NL80211_IFTYPE_ADHOC) || | 1489 | if ((ah->opmode == NL80211_IFTYPE_ADHOC) || |
1490 | ((vif->type == NL80211_IFTYPE_ADHOC) && | 1490 | ((vif->type == NL80211_IFTYPE_ADHOC) && |
1491 | sc->nvifs > 0)) { | 1491 | sc->nvifs > 0)) { |
1492 | ath_err(common, "Cannot create ADHOC interface when other" | 1492 | ath_err(common, "Cannot create ADHOC interface when other" |
1493 | " interfaces already exist.\n"); | 1493 | " interfaces already exist.\n"); |
1494 | ret = -EINVAL; | 1494 | ret = -EINVAL; |
1495 | goto out; | 1495 | goto out; |
1496 | } | 1496 | } |
1497 | 1497 | ||
1498 | ath_dbg(common, ATH_DBG_CONFIG, | 1498 | ath_dbg(common, ATH_DBG_CONFIG, |
1499 | "Attach a VIF of type: %d\n", vif->type); | 1499 | "Attach a VIF of type: %d\n", vif->type); |
1500 | 1500 | ||
1501 | sc->nvifs++; | 1501 | sc->nvifs++; |
1502 | 1502 | ||
1503 | ath9k_do_vif_add_setup(hw, vif); | 1503 | ath9k_do_vif_add_setup(hw, vif); |
1504 | out: | 1504 | out: |
1505 | mutex_unlock(&sc->mutex); | 1505 | mutex_unlock(&sc->mutex); |
1506 | ath9k_ps_restore(sc); | 1506 | ath9k_ps_restore(sc); |
1507 | return ret; | 1507 | return ret; |
1508 | } | 1508 | } |
1509 | 1509 | ||
1510 | static int ath9k_change_interface(struct ieee80211_hw *hw, | 1510 | static int ath9k_change_interface(struct ieee80211_hw *hw, |
1511 | struct ieee80211_vif *vif, | 1511 | struct ieee80211_vif *vif, |
1512 | enum nl80211_iftype new_type, | 1512 | enum nl80211_iftype new_type, |
1513 | bool p2p) | 1513 | bool p2p) |
1514 | { | 1514 | { |
1515 | struct ath_softc *sc = hw->priv; | 1515 | struct ath_softc *sc = hw->priv; |
1516 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1516 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1517 | int ret = 0; | 1517 | int ret = 0; |
1518 | 1518 | ||
1519 | ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n"); | 1519 | ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n"); |
1520 | mutex_lock(&sc->mutex); | 1520 | mutex_lock(&sc->mutex); |
1521 | ath9k_ps_wakeup(sc); | 1521 | ath9k_ps_wakeup(sc); |
1522 | 1522 | ||
1523 | /* See if new interface type is valid. */ | 1523 | /* See if new interface type is valid. */ |
1524 | if ((new_type == NL80211_IFTYPE_ADHOC) && | 1524 | if ((new_type == NL80211_IFTYPE_ADHOC) && |
1525 | (sc->nvifs > 1)) { | 1525 | (sc->nvifs > 1)) { |
1526 | ath_err(common, "When using ADHOC, it must be the only" | 1526 | ath_err(common, "When using ADHOC, it must be the only" |
1527 | " interface.\n"); | 1527 | " interface.\n"); |
1528 | ret = -EINVAL; | 1528 | ret = -EINVAL; |
1529 | goto out; | 1529 | goto out; |
1530 | } | 1530 | } |
1531 | 1531 | ||
1532 | if (ath9k_uses_beacons(new_type) && | 1532 | if (ath9k_uses_beacons(new_type) && |
1533 | !ath9k_uses_beacons(vif->type)) { | 1533 | !ath9k_uses_beacons(vif->type)) { |
1534 | if (sc->nbcnvifs >= ATH_BCBUF) { | 1534 | if (sc->nbcnvifs >= ATH_BCBUF) { |
1535 | ath_err(common, "No beacon slot available\n"); | 1535 | ath_err(common, "No beacon slot available\n"); |
1536 | ret = -ENOBUFS; | 1536 | ret = -ENOBUFS; |
1537 | goto out; | 1537 | goto out; |
1538 | } | 1538 | } |
1539 | } | 1539 | } |
1540 | 1540 | ||
1541 | /* Clean up old vif stuff */ | 1541 | /* Clean up old vif stuff */ |
1542 | if (ath9k_uses_beacons(vif->type)) | 1542 | if (ath9k_uses_beacons(vif->type)) |
1543 | ath9k_reclaim_beacon(sc, vif); | 1543 | ath9k_reclaim_beacon(sc, vif); |
1544 | 1544 | ||
1545 | /* Add new settings */ | 1545 | /* Add new settings */ |
1546 | vif->type = new_type; | 1546 | vif->type = new_type; |
1547 | vif->p2p = p2p; | 1547 | vif->p2p = p2p; |
1548 | 1548 | ||
1549 | ath9k_do_vif_add_setup(hw, vif); | 1549 | ath9k_do_vif_add_setup(hw, vif); |
1550 | out: | 1550 | out: |
1551 | ath9k_ps_restore(sc); | 1551 | ath9k_ps_restore(sc); |
1552 | mutex_unlock(&sc->mutex); | 1552 | mutex_unlock(&sc->mutex); |
1553 | return ret; | 1553 | return ret; |
1554 | } | 1554 | } |
1555 | 1555 | ||
1556 | static void ath9k_remove_interface(struct ieee80211_hw *hw, | 1556 | static void ath9k_remove_interface(struct ieee80211_hw *hw, |
1557 | struct ieee80211_vif *vif) | 1557 | struct ieee80211_vif *vif) |
1558 | { | 1558 | { |
1559 | struct ath_softc *sc = hw->priv; | 1559 | struct ath_softc *sc = hw->priv; |
1560 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1560 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1561 | 1561 | ||
1562 | ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n"); | 1562 | ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n"); |
1563 | 1563 | ||
1564 | ath9k_ps_wakeup(sc); | 1564 | ath9k_ps_wakeup(sc); |
1565 | mutex_lock(&sc->mutex); | 1565 | mutex_lock(&sc->mutex); |
1566 | 1566 | ||
1567 | sc->nvifs--; | 1567 | sc->nvifs--; |
1568 | 1568 | ||
1569 | /* Reclaim beacon resources */ | 1569 | /* Reclaim beacon resources */ |
1570 | if (ath9k_uses_beacons(vif->type)) | 1570 | if (ath9k_uses_beacons(vif->type)) |
1571 | ath9k_reclaim_beacon(sc, vif); | 1571 | ath9k_reclaim_beacon(sc, vif); |
1572 | 1572 | ||
1573 | ath9k_calculate_summary_state(hw, NULL); | 1573 | ath9k_calculate_summary_state(hw, NULL); |
1574 | 1574 | ||
1575 | mutex_unlock(&sc->mutex); | 1575 | mutex_unlock(&sc->mutex); |
1576 | ath9k_ps_restore(sc); | 1576 | ath9k_ps_restore(sc); |
1577 | } | 1577 | } |
1578 | 1578 | ||
1579 | static void ath9k_enable_ps(struct ath_softc *sc) | 1579 | static void ath9k_enable_ps(struct ath_softc *sc) |
1580 | { | 1580 | { |
1581 | struct ath_hw *ah = sc->sc_ah; | 1581 | struct ath_hw *ah = sc->sc_ah; |
1582 | 1582 | ||
1583 | sc->ps_enabled = true; | 1583 | sc->ps_enabled = true; |
1584 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { | 1584 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { |
1585 | if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) { | 1585 | if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) { |
1586 | ah->imask |= ATH9K_INT_TIM_TIMER; | 1586 | ah->imask |= ATH9K_INT_TIM_TIMER; |
1587 | ath9k_hw_set_interrupts(ah); | 1587 | ath9k_hw_set_interrupts(ah); |
1588 | } | 1588 | } |
1589 | ath9k_hw_setrxabort(ah, 1); | 1589 | ath9k_hw_setrxabort(ah, 1); |
1590 | } | 1590 | } |
1591 | } | 1591 | } |
1592 | 1592 | ||
1593 | static void ath9k_disable_ps(struct ath_softc *sc) | 1593 | static void ath9k_disable_ps(struct ath_softc *sc) |
1594 | { | 1594 | { |
1595 | struct ath_hw *ah = sc->sc_ah; | 1595 | struct ath_hw *ah = sc->sc_ah; |
1596 | 1596 | ||
1597 | sc->ps_enabled = false; | 1597 | sc->ps_enabled = false; |
1598 | ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); | 1598 | ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); |
1599 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { | 1599 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { |
1600 | ath9k_hw_setrxabort(ah, 0); | 1600 | ath9k_hw_setrxabort(ah, 0); |
1601 | sc->ps_flags &= ~(PS_WAIT_FOR_BEACON | | 1601 | sc->ps_flags &= ~(PS_WAIT_FOR_BEACON | |
1602 | PS_WAIT_FOR_CAB | | 1602 | PS_WAIT_FOR_CAB | |
1603 | PS_WAIT_FOR_PSPOLL_DATA | | 1603 | PS_WAIT_FOR_PSPOLL_DATA | |
1604 | PS_WAIT_FOR_TX_ACK); | 1604 | PS_WAIT_FOR_TX_ACK); |
1605 | if (ah->imask & ATH9K_INT_TIM_TIMER) { | 1605 | if (ah->imask & ATH9K_INT_TIM_TIMER) { |
1606 | ah->imask &= ~ATH9K_INT_TIM_TIMER; | 1606 | ah->imask &= ~ATH9K_INT_TIM_TIMER; |
1607 | ath9k_hw_set_interrupts(ah); | 1607 | ath9k_hw_set_interrupts(ah); |
1608 | } | 1608 | } |
1609 | } | 1609 | } |
1610 | 1610 | ||
1611 | } | 1611 | } |
1612 | 1612 | ||
1613 | static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | 1613 | static int ath9k_config(struct ieee80211_hw *hw, u32 changed) |
1614 | { | 1614 | { |
1615 | struct ath_softc *sc = hw->priv; | 1615 | struct ath_softc *sc = hw->priv; |
1616 | struct ath_hw *ah = sc->sc_ah; | 1616 | struct ath_hw *ah = sc->sc_ah; |
1617 | struct ath_common *common = ath9k_hw_common(ah); | 1617 | struct ath_common *common = ath9k_hw_common(ah); |
1618 | struct ieee80211_conf *conf = &hw->conf; | 1618 | struct ieee80211_conf *conf = &hw->conf; |
1619 | bool disable_radio = false; | 1619 | bool disable_radio = false; |
1620 | 1620 | ||
1621 | mutex_lock(&sc->mutex); | 1621 | mutex_lock(&sc->mutex); |
1622 | 1622 | ||
1623 | /* | 1623 | /* |
1624 | * Leave this as the first check because we need to turn on the | 1624 | * Leave this as the first check because we need to turn on the |
1625 | * radio if it was disabled before prior to processing the rest | 1625 | * radio if it was disabled before prior to processing the rest |
1626 | * of the changes. Likewise we must only disable the radio towards | 1626 | * of the changes. Likewise we must only disable the radio towards |
1627 | * the end. | 1627 | * the end. |
1628 | */ | 1628 | */ |
1629 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { | 1629 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { |
1630 | sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); | 1630 | sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); |
1631 | if (!sc->ps_idle) { | 1631 | if (!sc->ps_idle) { |
1632 | ath_radio_enable(sc, hw); | 1632 | ath_radio_enable(sc, hw); |
1633 | ath_dbg(common, ATH_DBG_CONFIG, | 1633 | ath_dbg(common, ATH_DBG_CONFIG, |
1634 | "not-idle: enabling radio\n"); | 1634 | "not-idle: enabling radio\n"); |
1635 | } else { | 1635 | } else { |
1636 | disable_radio = true; | 1636 | disable_radio = true; |
1637 | } | 1637 | } |
1638 | } | 1638 | } |
1639 | 1639 | ||
1640 | /* | 1640 | /* |
1641 | * We just prepare to enable PS. We have to wait until our AP has | 1641 | * We just prepare to enable PS. We have to wait until our AP has |
1642 | * ACK'd our null data frame to disable RX otherwise we'll ignore | 1642 | * ACK'd our null data frame to disable RX otherwise we'll ignore |
1643 | * those ACKs and end up retransmitting the same null data frames. | 1643 | * those ACKs and end up retransmitting the same null data frames. |
1644 | * IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode. | 1644 | * IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode. |
1645 | */ | 1645 | */ |
1646 | if (changed & IEEE80211_CONF_CHANGE_PS) { | 1646 | if (changed & IEEE80211_CONF_CHANGE_PS) { |
1647 | unsigned long flags; | 1647 | unsigned long flags; |
1648 | spin_lock_irqsave(&sc->sc_pm_lock, flags); | 1648 | spin_lock_irqsave(&sc->sc_pm_lock, flags); |
1649 | if (conf->flags & IEEE80211_CONF_PS) | 1649 | if (conf->flags & IEEE80211_CONF_PS) |
1650 | ath9k_enable_ps(sc); | 1650 | ath9k_enable_ps(sc); |
1651 | else | 1651 | else |
1652 | ath9k_disable_ps(sc); | 1652 | ath9k_disable_ps(sc); |
1653 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | 1653 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); |
1654 | } | 1654 | } |
1655 | 1655 | ||
1656 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { | 1656 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { |
1657 | if (conf->flags & IEEE80211_CONF_MONITOR) { | 1657 | if (conf->flags & IEEE80211_CONF_MONITOR) { |
1658 | ath_dbg(common, ATH_DBG_CONFIG, | 1658 | ath_dbg(common, ATH_DBG_CONFIG, |
1659 | "Monitor mode is enabled\n"); | 1659 | "Monitor mode is enabled\n"); |
1660 | sc->sc_ah->is_monitoring = true; | 1660 | sc->sc_ah->is_monitoring = true; |
1661 | } else { | 1661 | } else { |
1662 | ath_dbg(common, ATH_DBG_CONFIG, | 1662 | ath_dbg(common, ATH_DBG_CONFIG, |
1663 | "Monitor mode is disabled\n"); | 1663 | "Monitor mode is disabled\n"); |
1664 | sc->sc_ah->is_monitoring = false; | 1664 | sc->sc_ah->is_monitoring = false; |
1665 | } | 1665 | } |
1666 | } | 1666 | } |
1667 | 1667 | ||
1668 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | 1668 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { |
1669 | struct ieee80211_channel *curchan = hw->conf.channel; | 1669 | struct ieee80211_channel *curchan = hw->conf.channel; |
1670 | struct ath9k_channel old_chan; | 1670 | struct ath9k_channel old_chan; |
1671 | int pos = curchan->hw_value; | 1671 | int pos = curchan->hw_value; |
1672 | int old_pos = -1; | 1672 | int old_pos = -1; |
1673 | unsigned long flags; | 1673 | unsigned long flags; |
1674 | 1674 | ||
1675 | if (ah->curchan) | 1675 | if (ah->curchan) |
1676 | old_pos = ah->curchan - &ah->channels[0]; | 1676 | old_pos = ah->curchan - &ah->channels[0]; |
1677 | 1677 | ||
1678 | if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) | 1678 | if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) |
1679 | sc->sc_flags |= SC_OP_OFFCHANNEL; | 1679 | sc->sc_flags |= SC_OP_OFFCHANNEL; |
1680 | else | 1680 | else |
1681 | sc->sc_flags &= ~SC_OP_OFFCHANNEL; | 1681 | sc->sc_flags &= ~SC_OP_OFFCHANNEL; |
1682 | 1682 | ||
1683 | ath_dbg(common, ATH_DBG_CONFIG, | 1683 | ath_dbg(common, ATH_DBG_CONFIG, |
1684 | "Set channel: %d MHz type: %d\n", | 1684 | "Set channel: %d MHz type: %d\n", |
1685 | curchan->center_freq, conf->channel_type); | 1685 | curchan->center_freq, conf->channel_type); |
1686 | 1686 | ||
1687 | /* update survey stats for the old channel before switching */ | 1687 | /* update survey stats for the old channel before switching */ |
1688 | spin_lock_irqsave(&common->cc_lock, flags); | 1688 | spin_lock_irqsave(&common->cc_lock, flags); |
1689 | ath_update_survey_stats(sc); | 1689 | ath_update_survey_stats(sc); |
1690 | spin_unlock_irqrestore(&common->cc_lock, flags); | 1690 | spin_unlock_irqrestore(&common->cc_lock, flags); |
1691 | 1691 | ||
1692 | /* | 1692 | /* |
1693 | * Preserve the current channel values, before updating | 1693 | * Preserve the current channel values, before updating |
1694 | * the same channel | 1694 | * the same channel |
1695 | */ | 1695 | */ |
1696 | if (old_pos == pos) { | 1696 | if (old_pos == pos) { |
1697 | memcpy(&old_chan, &sc->sc_ah->channels[pos], | 1697 | memcpy(&old_chan, &sc->sc_ah->channels[pos], |
1698 | sizeof(struct ath9k_channel)); | 1698 | sizeof(struct ath9k_channel)); |
1699 | ah->curchan = &old_chan; | 1699 | ah->curchan = &old_chan; |
1700 | } | 1700 | } |
1701 | 1701 | ||
1702 | ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], | 1702 | ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], |
1703 | curchan, conf->channel_type); | 1703 | curchan, conf->channel_type); |
1704 | 1704 | ||
1705 | /* | 1705 | /* |
1706 | * If the operating channel changes, change the survey in-use flags | 1706 | * If the operating channel changes, change the survey in-use flags |
1707 | * along with it. | 1707 | * along with it. |
1708 | * Reset the survey data for the new channel, unless we're switching | 1708 | * Reset the survey data for the new channel, unless we're switching |
1709 | * back to the operating channel from an off-channel operation. | 1709 | * back to the operating channel from an off-channel operation. |
1710 | */ | 1710 | */ |
1711 | if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && | 1711 | if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && |
1712 | sc->cur_survey != &sc->survey[pos]) { | 1712 | sc->cur_survey != &sc->survey[pos]) { |
1713 | 1713 | ||
1714 | if (sc->cur_survey) | 1714 | if (sc->cur_survey) |
1715 | sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; | 1715 | sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; |
1716 | 1716 | ||
1717 | sc->cur_survey = &sc->survey[pos]; | 1717 | sc->cur_survey = &sc->survey[pos]; |
1718 | 1718 | ||
1719 | memset(sc->cur_survey, 0, sizeof(struct survey_info)); | 1719 | memset(sc->cur_survey, 0, sizeof(struct survey_info)); |
1720 | sc->cur_survey->filled |= SURVEY_INFO_IN_USE; | 1720 | sc->cur_survey->filled |= SURVEY_INFO_IN_USE; |
1721 | } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { | 1721 | } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { |
1722 | memset(&sc->survey[pos], 0, sizeof(struct survey_info)); | 1722 | memset(&sc->survey[pos], 0, sizeof(struct survey_info)); |
1723 | } | 1723 | } |
1724 | 1724 | ||
1725 | if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { | 1725 | if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { |
1726 | ath_err(common, "Unable to set channel\n"); | 1726 | ath_err(common, "Unable to set channel\n"); |
1727 | mutex_unlock(&sc->mutex); | 1727 | mutex_unlock(&sc->mutex); |
1728 | return -EINVAL; | 1728 | return -EINVAL; |
1729 | } | 1729 | } |
1730 | 1730 | ||
1731 | /* | 1731 | /* |
1732 | * The most recent snapshot of channel->noisefloor for the old | 1732 | * The most recent snapshot of channel->noisefloor for the old |
1733 | * channel is only available after the hardware reset. Copy it to | 1733 | * channel is only available after the hardware reset. Copy it to |
1734 | * the survey stats now. | 1734 | * the survey stats now. |
1735 | */ | 1735 | */ |
1736 | if (old_pos >= 0) | 1736 | if (old_pos >= 0) |
1737 | ath_update_survey_nf(sc, old_pos); | 1737 | ath_update_survey_nf(sc, old_pos); |
1738 | } | 1738 | } |
1739 | 1739 | ||
1740 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | 1740 | if (changed & IEEE80211_CONF_CHANGE_POWER) { |
1741 | ath_dbg(common, ATH_DBG_CONFIG, | 1741 | ath_dbg(common, ATH_DBG_CONFIG, |
1742 | "Set power: %d\n", conf->power_level); | 1742 | "Set power: %d\n", conf->power_level); |
1743 | sc->config.txpowlimit = 2 * conf->power_level; | 1743 | sc->config.txpowlimit = 2 * conf->power_level; |
1744 | ath9k_ps_wakeup(sc); | 1744 | ath9k_ps_wakeup(sc); |
1745 | ath9k_cmn_update_txpow(ah, sc->curtxpow, | 1745 | ath9k_cmn_update_txpow(ah, sc->curtxpow, |
1746 | sc->config.txpowlimit, &sc->curtxpow); | 1746 | sc->config.txpowlimit, &sc->curtxpow); |
1747 | ath9k_ps_restore(sc); | 1747 | ath9k_ps_restore(sc); |
1748 | } | 1748 | } |
1749 | 1749 | ||
1750 | if (disable_radio) { | 1750 | if (disable_radio) { |
1751 | ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); | 1751 | ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); |
1752 | ath_radio_disable(sc, hw); | 1752 | ath_radio_disable(sc, hw); |
1753 | } | 1753 | } |
1754 | 1754 | ||
1755 | mutex_unlock(&sc->mutex); | 1755 | mutex_unlock(&sc->mutex); |
1756 | 1756 | ||
1757 | return 0; | 1757 | return 0; |
1758 | } | 1758 | } |
1759 | 1759 | ||
1760 | #define SUPPORTED_FILTERS \ | 1760 | #define SUPPORTED_FILTERS \ |
1761 | (FIF_PROMISC_IN_BSS | \ | 1761 | (FIF_PROMISC_IN_BSS | \ |
1762 | FIF_ALLMULTI | \ | 1762 | FIF_ALLMULTI | \ |
1763 | FIF_CONTROL | \ | 1763 | FIF_CONTROL | \ |
1764 | FIF_PSPOLL | \ | 1764 | FIF_PSPOLL | \ |
1765 | FIF_OTHER_BSS | \ | 1765 | FIF_OTHER_BSS | \ |
1766 | FIF_BCN_PRBRESP_PROMISC | \ | 1766 | FIF_BCN_PRBRESP_PROMISC | \ |
1767 | FIF_PROBE_REQ | \ | 1767 | FIF_PROBE_REQ | \ |
1768 | FIF_FCSFAIL) | 1768 | FIF_FCSFAIL) |
1769 | 1769 | ||
1770 | /* FIXME: sc->sc_full_reset ? */ | 1770 | /* FIXME: sc->sc_full_reset ? */ |
1771 | static void ath9k_configure_filter(struct ieee80211_hw *hw, | 1771 | static void ath9k_configure_filter(struct ieee80211_hw *hw, |
1772 | unsigned int changed_flags, | 1772 | unsigned int changed_flags, |
1773 | unsigned int *total_flags, | 1773 | unsigned int *total_flags, |
1774 | u64 multicast) | 1774 | u64 multicast) |
1775 | { | 1775 | { |
1776 | struct ath_softc *sc = hw->priv; | 1776 | struct ath_softc *sc = hw->priv; |
1777 | u32 rfilt; | 1777 | u32 rfilt; |
1778 | 1778 | ||
1779 | changed_flags &= SUPPORTED_FILTERS; | 1779 | changed_flags &= SUPPORTED_FILTERS; |
1780 | *total_flags &= SUPPORTED_FILTERS; | 1780 | *total_flags &= SUPPORTED_FILTERS; |
1781 | 1781 | ||
1782 | sc->rx.rxfilter = *total_flags; | 1782 | sc->rx.rxfilter = *total_flags; |
1783 | ath9k_ps_wakeup(sc); | 1783 | ath9k_ps_wakeup(sc); |
1784 | rfilt = ath_calcrxfilter(sc); | 1784 | rfilt = ath_calcrxfilter(sc); |
1785 | ath9k_hw_setrxfilter(sc->sc_ah, rfilt); | 1785 | ath9k_hw_setrxfilter(sc->sc_ah, rfilt); |
1786 | ath9k_ps_restore(sc); | 1786 | ath9k_ps_restore(sc); |
1787 | 1787 | ||
1788 | ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, | 1788 | ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, |
1789 | "Set HW RX filter: 0x%x\n", rfilt); | 1789 | "Set HW RX filter: 0x%x\n", rfilt); |
1790 | } | 1790 | } |
1791 | 1791 | ||
1792 | static int ath9k_sta_add(struct ieee80211_hw *hw, | 1792 | static int ath9k_sta_add(struct ieee80211_hw *hw, |
1793 | struct ieee80211_vif *vif, | 1793 | struct ieee80211_vif *vif, |
1794 | struct ieee80211_sta *sta) | 1794 | struct ieee80211_sta *sta) |
1795 | { | 1795 | { |
1796 | struct ath_softc *sc = hw->priv; | 1796 | struct ath_softc *sc = hw->priv; |
1797 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1797 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1798 | struct ath_node *an = (struct ath_node *) sta->drv_priv; | 1798 | struct ath_node *an = (struct ath_node *) sta->drv_priv; |
1799 | struct ieee80211_key_conf ps_key = { }; | 1799 | struct ieee80211_key_conf ps_key = { }; |
1800 | 1800 | ||
1801 | ath_node_attach(sc, sta); | 1801 | ath_node_attach(sc, sta); |
1802 | 1802 | ||
1803 | if (vif->type != NL80211_IFTYPE_AP && | 1803 | if (vif->type != NL80211_IFTYPE_AP && |
1804 | vif->type != NL80211_IFTYPE_AP_VLAN) | 1804 | vif->type != NL80211_IFTYPE_AP_VLAN) |
1805 | return 0; | 1805 | return 0; |
1806 | 1806 | ||
1807 | an->ps_key = ath_key_config(common, vif, sta, &ps_key); | 1807 | an->ps_key = ath_key_config(common, vif, sta, &ps_key); |
1808 | 1808 | ||
1809 | return 0; | 1809 | return 0; |
1810 | } | 1810 | } |
1811 | 1811 | ||
1812 | static void ath9k_del_ps_key(struct ath_softc *sc, | 1812 | static void ath9k_del_ps_key(struct ath_softc *sc, |
1813 | struct ieee80211_vif *vif, | 1813 | struct ieee80211_vif *vif, |
1814 | struct ieee80211_sta *sta) | 1814 | struct ieee80211_sta *sta) |
1815 | { | 1815 | { |
1816 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1816 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1817 | struct ath_node *an = (struct ath_node *) sta->drv_priv; | 1817 | struct ath_node *an = (struct ath_node *) sta->drv_priv; |
1818 | struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key }; | 1818 | struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key }; |
1819 | 1819 | ||
1820 | if (!an->ps_key) | 1820 | if (!an->ps_key) |
1821 | return; | 1821 | return; |
1822 | 1822 | ||
1823 | ath_key_delete(common, &ps_key); | 1823 | ath_key_delete(common, &ps_key); |
1824 | } | 1824 | } |
1825 | 1825 | ||
1826 | static int ath9k_sta_remove(struct ieee80211_hw *hw, | 1826 | static int ath9k_sta_remove(struct ieee80211_hw *hw, |
1827 | struct ieee80211_vif *vif, | 1827 | struct ieee80211_vif *vif, |
1828 | struct ieee80211_sta *sta) | 1828 | struct ieee80211_sta *sta) |
1829 | { | 1829 | { |
1830 | struct ath_softc *sc = hw->priv; | 1830 | struct ath_softc *sc = hw->priv; |
1831 | 1831 | ||
1832 | ath9k_del_ps_key(sc, vif, sta); | 1832 | ath9k_del_ps_key(sc, vif, sta); |
1833 | ath_node_detach(sc, sta); | 1833 | ath_node_detach(sc, sta); |
1834 | 1834 | ||
1835 | return 0; | 1835 | return 0; |
1836 | } | 1836 | } |
1837 | 1837 | ||
1838 | static void ath9k_sta_notify(struct ieee80211_hw *hw, | 1838 | static void ath9k_sta_notify(struct ieee80211_hw *hw, |
1839 | struct ieee80211_vif *vif, | 1839 | struct ieee80211_vif *vif, |
1840 | enum sta_notify_cmd cmd, | 1840 | enum sta_notify_cmd cmd, |
1841 | struct ieee80211_sta *sta) | 1841 | struct ieee80211_sta *sta) |
1842 | { | 1842 | { |
1843 | struct ath_softc *sc = hw->priv; | 1843 | struct ath_softc *sc = hw->priv; |
1844 | struct ath_node *an = (struct ath_node *) sta->drv_priv; | 1844 | struct ath_node *an = (struct ath_node *) sta->drv_priv; |
1845 | 1845 | ||
1846 | if (!(sc->sc_flags & SC_OP_TXAGGR)) | ||
1847 | return; | ||
1848 | |||
1846 | switch (cmd) { | 1849 | switch (cmd) { |
1847 | case STA_NOTIFY_SLEEP: | 1850 | case STA_NOTIFY_SLEEP: |
1848 | an->sleeping = true; | 1851 | an->sleeping = true; |
1849 | ath_tx_aggr_sleep(sta, sc, an); | 1852 | ath_tx_aggr_sleep(sta, sc, an); |
1850 | break; | 1853 | break; |
1851 | case STA_NOTIFY_AWAKE: | 1854 | case STA_NOTIFY_AWAKE: |
1852 | an->sleeping = false; | 1855 | an->sleeping = false; |
1853 | ath_tx_aggr_wakeup(sc, an); | 1856 | ath_tx_aggr_wakeup(sc, an); |
1854 | break; | 1857 | break; |
1855 | } | 1858 | } |
1856 | } | 1859 | } |
1857 | 1860 | ||
1858 | static int ath9k_conf_tx(struct ieee80211_hw *hw, | 1861 | static int ath9k_conf_tx(struct ieee80211_hw *hw, |
1859 | struct ieee80211_vif *vif, u16 queue, | 1862 | struct ieee80211_vif *vif, u16 queue, |
1860 | const struct ieee80211_tx_queue_params *params) | 1863 | const struct ieee80211_tx_queue_params *params) |
1861 | { | 1864 | { |
1862 | struct ath_softc *sc = hw->priv; | 1865 | struct ath_softc *sc = hw->priv; |
1863 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1866 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1864 | struct ath_txq *txq; | 1867 | struct ath_txq *txq; |
1865 | struct ath9k_tx_queue_info qi; | 1868 | struct ath9k_tx_queue_info qi; |
1866 | int ret = 0; | 1869 | int ret = 0; |
1867 | 1870 | ||
1868 | if (queue >= WME_NUM_AC) | 1871 | if (queue >= WME_NUM_AC) |
1869 | return 0; | 1872 | return 0; |
1870 | 1873 | ||
1871 | txq = sc->tx.txq_map[queue]; | 1874 | txq = sc->tx.txq_map[queue]; |
1872 | 1875 | ||
1873 | ath9k_ps_wakeup(sc); | 1876 | ath9k_ps_wakeup(sc); |
1874 | mutex_lock(&sc->mutex); | 1877 | mutex_lock(&sc->mutex); |
1875 | 1878 | ||
1876 | memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); | 1879 | memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); |
1877 | 1880 | ||
1878 | qi.tqi_aifs = params->aifs; | 1881 | qi.tqi_aifs = params->aifs; |
1879 | qi.tqi_cwmin = params->cw_min; | 1882 | qi.tqi_cwmin = params->cw_min; |
1880 | qi.tqi_cwmax = params->cw_max; | 1883 | qi.tqi_cwmax = params->cw_max; |
1881 | qi.tqi_burstTime = params->txop; | 1884 | qi.tqi_burstTime = params->txop; |
1882 | 1885 | ||
1883 | ath_dbg(common, ATH_DBG_CONFIG, | 1886 | ath_dbg(common, ATH_DBG_CONFIG, |
1884 | "Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", | 1887 | "Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", |
1885 | queue, txq->axq_qnum, params->aifs, params->cw_min, | 1888 | queue, txq->axq_qnum, params->aifs, params->cw_min, |
1886 | params->cw_max, params->txop); | 1889 | params->cw_max, params->txop); |
1887 | 1890 | ||
1888 | ret = ath_txq_update(sc, txq->axq_qnum, &qi); | 1891 | ret = ath_txq_update(sc, txq->axq_qnum, &qi); |
1889 | if (ret) | 1892 | if (ret) |
1890 | ath_err(common, "TXQ Update failed\n"); | 1893 | ath_err(common, "TXQ Update failed\n"); |
1891 | 1894 | ||
1892 | if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) | 1895 | if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) |
1893 | if (queue == WME_AC_BE && !ret) | 1896 | if (queue == WME_AC_BE && !ret) |
1894 | ath_beaconq_config(sc); | 1897 | ath_beaconq_config(sc); |
1895 | 1898 | ||
1896 | mutex_unlock(&sc->mutex); | 1899 | mutex_unlock(&sc->mutex); |
1897 | ath9k_ps_restore(sc); | 1900 | ath9k_ps_restore(sc); |
1898 | 1901 | ||
1899 | return ret; | 1902 | return ret; |
1900 | } | 1903 | } |
1901 | 1904 | ||
1902 | static int ath9k_set_key(struct ieee80211_hw *hw, | 1905 | static int ath9k_set_key(struct ieee80211_hw *hw, |
1903 | enum set_key_cmd cmd, | 1906 | enum set_key_cmd cmd, |
1904 | struct ieee80211_vif *vif, | 1907 | struct ieee80211_vif *vif, |
1905 | struct ieee80211_sta *sta, | 1908 | struct ieee80211_sta *sta, |
1906 | struct ieee80211_key_conf *key) | 1909 | struct ieee80211_key_conf *key) |
1907 | { | 1910 | { |
1908 | struct ath_softc *sc = hw->priv; | 1911 | struct ath_softc *sc = hw->priv; |
1909 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1912 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1910 | int ret = 0; | 1913 | int ret = 0; |
1911 | 1914 | ||
1912 | if (ath9k_modparam_nohwcrypt) | 1915 | if (ath9k_modparam_nohwcrypt) |
1913 | return -ENOSPC; | 1916 | return -ENOSPC; |
1914 | 1917 | ||
1915 | if (vif->type == NL80211_IFTYPE_ADHOC && | 1918 | if (vif->type == NL80211_IFTYPE_ADHOC && |
1916 | (key->cipher == WLAN_CIPHER_SUITE_TKIP || | 1919 | (key->cipher == WLAN_CIPHER_SUITE_TKIP || |
1917 | key->cipher == WLAN_CIPHER_SUITE_CCMP) && | 1920 | key->cipher == WLAN_CIPHER_SUITE_CCMP) && |
1918 | !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { | 1921 | !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { |
1919 | /* | 1922 | /* |
1920 | * For now, disable hw crypto for the RSN IBSS group keys. This | 1923 | * For now, disable hw crypto for the RSN IBSS group keys. This |
1921 | * could be optimized in the future to use a modified key cache | 1924 | * could be optimized in the future to use a modified key cache |
1922 | * design to support per-STA RX GTK, but until that gets | 1925 | * design to support per-STA RX GTK, but until that gets |
1923 | * implemented, use of software crypto for group addressed | 1926 | * implemented, use of software crypto for group addressed |
1924 | * frames is a acceptable to allow RSN IBSS to be used. | 1927 | * frames is a acceptable to allow RSN IBSS to be used. |
1925 | */ | 1928 | */ |
1926 | return -EOPNOTSUPP; | 1929 | return -EOPNOTSUPP; |
1927 | } | 1930 | } |
1928 | 1931 | ||
1929 | mutex_lock(&sc->mutex); | 1932 | mutex_lock(&sc->mutex); |
1930 | ath9k_ps_wakeup(sc); | 1933 | ath9k_ps_wakeup(sc); |
1931 | ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n"); | 1934 | ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n"); |
1932 | 1935 | ||
1933 | switch (cmd) { | 1936 | switch (cmd) { |
1934 | case SET_KEY: | 1937 | case SET_KEY: |
1935 | if (sta) | 1938 | if (sta) |
1936 | ath9k_del_ps_key(sc, vif, sta); | 1939 | ath9k_del_ps_key(sc, vif, sta); |
1937 | 1940 | ||
1938 | ret = ath_key_config(common, vif, sta, key); | 1941 | ret = ath_key_config(common, vif, sta, key); |
1939 | if (ret >= 0) { | 1942 | if (ret >= 0) { |
1940 | key->hw_key_idx = ret; | 1943 | key->hw_key_idx = ret; |
1941 | /* push IV and Michael MIC generation to stack */ | 1944 | /* push IV and Michael MIC generation to stack */ |
1942 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 1945 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; |
1943 | if (key->cipher == WLAN_CIPHER_SUITE_TKIP) | 1946 | if (key->cipher == WLAN_CIPHER_SUITE_TKIP) |
1944 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | 1947 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; |
1945 | if (sc->sc_ah->sw_mgmt_crypto && | 1948 | if (sc->sc_ah->sw_mgmt_crypto && |
1946 | key->cipher == WLAN_CIPHER_SUITE_CCMP) | 1949 | key->cipher == WLAN_CIPHER_SUITE_CCMP) |
1947 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; | 1950 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; |
1948 | ret = 0; | 1951 | ret = 0; |
1949 | } | 1952 | } |
1950 | break; | 1953 | break; |
1951 | case DISABLE_KEY: | 1954 | case DISABLE_KEY: |
1952 | ath_key_delete(common, key); | 1955 | ath_key_delete(common, key); |
1953 | break; | 1956 | break; |
1954 | default: | 1957 | default: |
1955 | ret = -EINVAL; | 1958 | ret = -EINVAL; |
1956 | } | 1959 | } |
1957 | 1960 | ||
1958 | ath9k_ps_restore(sc); | 1961 | ath9k_ps_restore(sc); |
1959 | mutex_unlock(&sc->mutex); | 1962 | mutex_unlock(&sc->mutex); |
1960 | 1963 | ||
1961 | return ret; | 1964 | return ret; |
1962 | } | 1965 | } |
1963 | static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | 1966 | static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) |
1964 | { | 1967 | { |
1965 | struct ath_softc *sc = data; | 1968 | struct ath_softc *sc = data; |
1966 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1969 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1967 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | 1970 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
1968 | struct ath_vif *avp = (void *)vif->drv_priv; | 1971 | struct ath_vif *avp = (void *)vif->drv_priv; |
1969 | 1972 | ||
1970 | /* | 1973 | /* |
1971 | * Skip iteration if primary station vif's bss info | 1974 | * Skip iteration if primary station vif's bss info |
1972 | * was not changed | 1975 | * was not changed |
1973 | */ | 1976 | */ |
1974 | if (sc->sc_flags & SC_OP_PRIM_STA_VIF) | 1977 | if (sc->sc_flags & SC_OP_PRIM_STA_VIF) |
1975 | return; | 1978 | return; |
1976 | 1979 | ||
1977 | if (bss_conf->assoc) { | 1980 | if (bss_conf->assoc) { |
1978 | sc->sc_flags |= SC_OP_PRIM_STA_VIF; | 1981 | sc->sc_flags |= SC_OP_PRIM_STA_VIF; |
1979 | avp->primary_sta_vif = true; | 1982 | avp->primary_sta_vif = true; |
1980 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); | 1983 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); |
1981 | common->curaid = bss_conf->aid; | 1984 | common->curaid = bss_conf->aid; |
1982 | ath9k_hw_write_associd(sc->sc_ah); | 1985 | ath9k_hw_write_associd(sc->sc_ah); |
1983 | ath_dbg(common, ATH_DBG_CONFIG, | 1986 | ath_dbg(common, ATH_DBG_CONFIG, |
1984 | "Bss Info ASSOC %d, bssid: %pM\n", | 1987 | "Bss Info ASSOC %d, bssid: %pM\n", |
1985 | bss_conf->aid, common->curbssid); | 1988 | bss_conf->aid, common->curbssid); |
1986 | ath_beacon_config(sc, vif); | 1989 | ath_beacon_config(sc, vif); |
1987 | /* | 1990 | /* |
1988 | * Request a re-configuration of Beacon related timers | 1991 | * Request a re-configuration of Beacon related timers |
1989 | * on the receipt of the first Beacon frame (i.e., | 1992 | * on the receipt of the first Beacon frame (i.e., |
1990 | * after time sync with the AP). | 1993 | * after time sync with the AP). |
1991 | */ | 1994 | */ |
1992 | sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; | 1995 | sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; |
1993 | /* Reset rssi stats */ | 1996 | /* Reset rssi stats */ |
1994 | sc->last_rssi = ATH_RSSI_DUMMY_MARKER; | 1997 | sc->last_rssi = ATH_RSSI_DUMMY_MARKER; |
1995 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; | 1998 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; |
1996 | 1999 | ||
1997 | if (!common->disable_ani) { | 2000 | if (!common->disable_ani) { |
1998 | sc->sc_flags |= SC_OP_ANI_RUN; | 2001 | sc->sc_flags |= SC_OP_ANI_RUN; |
1999 | ath_start_ani(common); | 2002 | ath_start_ani(common); |
2000 | } | 2003 | } |
2001 | 2004 | ||
2002 | } | 2005 | } |
2003 | } | 2006 | } |
2004 | 2007 | ||
2005 | static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) | 2008 | static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) |
2006 | { | 2009 | { |
2007 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 2010 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
2008 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | 2011 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
2009 | struct ath_vif *avp = (void *)vif->drv_priv; | 2012 | struct ath_vif *avp = (void *)vif->drv_priv; |
2010 | 2013 | ||
2011 | if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) | 2014 | if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) |
2012 | return; | 2015 | return; |
2013 | 2016 | ||
2014 | /* Reconfigure bss info */ | 2017 | /* Reconfigure bss info */ |
2015 | if (avp->primary_sta_vif && !bss_conf->assoc) { | 2018 | if (avp->primary_sta_vif && !bss_conf->assoc) { |
2016 | ath_dbg(common, ATH_DBG_CONFIG, | 2019 | ath_dbg(common, ATH_DBG_CONFIG, |
2017 | "Bss Info DISASSOC %d, bssid %pM\n", | 2020 | "Bss Info DISASSOC %d, bssid %pM\n", |
2018 | common->curaid, common->curbssid); | 2021 | common->curaid, common->curbssid); |
2019 | sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS); | 2022 | sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS); |
2020 | avp->primary_sta_vif = false; | 2023 | avp->primary_sta_vif = false; |
2021 | memset(common->curbssid, 0, ETH_ALEN); | 2024 | memset(common->curbssid, 0, ETH_ALEN); |
2022 | common->curaid = 0; | 2025 | common->curaid = 0; |
2023 | } | 2026 | } |
2024 | 2027 | ||
2025 | ieee80211_iterate_active_interfaces_atomic( | 2028 | ieee80211_iterate_active_interfaces_atomic( |
2026 | sc->hw, ath9k_bss_iter, sc); | 2029 | sc->hw, ath9k_bss_iter, sc); |
2027 | 2030 | ||
2028 | /* | 2031 | /* |
2029 | * None of station vifs are associated. | 2032 | * None of station vifs are associated. |
2030 | * Clear bssid & aid | 2033 | * Clear bssid & aid |
2031 | */ | 2034 | */ |
2032 | if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) { | 2035 | if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) { |
2033 | ath9k_hw_write_associd(sc->sc_ah); | 2036 | ath9k_hw_write_associd(sc->sc_ah); |
2034 | /* Stop ANI */ | 2037 | /* Stop ANI */ |
2035 | sc->sc_flags &= ~SC_OP_ANI_RUN; | 2038 | sc->sc_flags &= ~SC_OP_ANI_RUN; |
2036 | del_timer_sync(&common->ani.timer); | 2039 | del_timer_sync(&common->ani.timer); |
2037 | memset(&sc->caldata, 0, sizeof(sc->caldata)); | 2040 | memset(&sc->caldata, 0, sizeof(sc->caldata)); |
2038 | } | 2041 | } |
2039 | } | 2042 | } |
2040 | 2043 | ||
2041 | static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | 2044 | static void ath9k_bss_info_changed(struct ieee80211_hw *hw, |
2042 | struct ieee80211_vif *vif, | 2045 | struct ieee80211_vif *vif, |
2043 | struct ieee80211_bss_conf *bss_conf, | 2046 | struct ieee80211_bss_conf *bss_conf, |
2044 | u32 changed) | 2047 | u32 changed) |
2045 | { | 2048 | { |
2046 | struct ath_softc *sc = hw->priv; | 2049 | struct ath_softc *sc = hw->priv; |
2047 | struct ath_hw *ah = sc->sc_ah; | 2050 | struct ath_hw *ah = sc->sc_ah; |
2048 | struct ath_common *common = ath9k_hw_common(ah); | 2051 | struct ath_common *common = ath9k_hw_common(ah); |
2049 | struct ath_vif *avp = (void *)vif->drv_priv; | 2052 | struct ath_vif *avp = (void *)vif->drv_priv; |
2050 | int slottime; | 2053 | int slottime; |
2051 | int error; | 2054 | int error; |
2052 | 2055 | ||
2053 | ath9k_ps_wakeup(sc); | 2056 | ath9k_ps_wakeup(sc); |
2054 | mutex_lock(&sc->mutex); | 2057 | mutex_lock(&sc->mutex); |
2055 | 2058 | ||
2056 | if (changed & BSS_CHANGED_BSSID) { | 2059 | if (changed & BSS_CHANGED_BSSID) { |
2057 | ath9k_config_bss(sc, vif); | 2060 | ath9k_config_bss(sc, vif); |
2058 | 2061 | ||
2059 | ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n", | 2062 | ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n", |
2060 | common->curbssid, common->curaid); | 2063 | common->curbssid, common->curaid); |
2061 | } | 2064 | } |
2062 | 2065 | ||
2063 | if (changed & BSS_CHANGED_IBSS) { | 2066 | if (changed & BSS_CHANGED_IBSS) { |
2064 | /* There can be only one vif available */ | 2067 | /* There can be only one vif available */ |
2065 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); | 2068 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); |
2066 | common->curaid = bss_conf->aid; | 2069 | common->curaid = bss_conf->aid; |
2067 | ath9k_hw_write_associd(sc->sc_ah); | 2070 | ath9k_hw_write_associd(sc->sc_ah); |
2068 | 2071 | ||
2069 | if (bss_conf->ibss_joined) { | 2072 | if (bss_conf->ibss_joined) { |
2070 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; | 2073 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; |
2071 | 2074 | ||
2072 | if (!common->disable_ani) { | 2075 | if (!common->disable_ani) { |
2073 | sc->sc_flags |= SC_OP_ANI_RUN; | 2076 | sc->sc_flags |= SC_OP_ANI_RUN; |
2074 | ath_start_ani(common); | 2077 | ath_start_ani(common); |
2075 | } | 2078 | } |
2076 | 2079 | ||
2077 | } else { | 2080 | } else { |
2078 | sc->sc_flags &= ~SC_OP_ANI_RUN; | 2081 | sc->sc_flags &= ~SC_OP_ANI_RUN; |
2079 | del_timer_sync(&common->ani.timer); | 2082 | del_timer_sync(&common->ani.timer); |
2080 | } | 2083 | } |
2081 | } | 2084 | } |
2082 | 2085 | ||
2083 | /* Enable transmission of beacons (AP, IBSS, MESH) */ | 2086 | /* Enable transmission of beacons (AP, IBSS, MESH) */ |
2084 | if ((changed & BSS_CHANGED_BEACON) || | 2087 | if ((changed & BSS_CHANGED_BEACON) || |
2085 | ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) { | 2088 | ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) { |
2086 | ath9k_set_beaconing_status(sc, false); | 2089 | ath9k_set_beaconing_status(sc, false); |
2087 | error = ath_beacon_alloc(sc, vif); | 2090 | error = ath_beacon_alloc(sc, vif); |
2088 | if (!error) | 2091 | if (!error) |
2089 | ath_beacon_config(sc, vif); | 2092 | ath_beacon_config(sc, vif); |
2090 | ath9k_set_beaconing_status(sc, true); | 2093 | ath9k_set_beaconing_status(sc, true); |
2091 | } | 2094 | } |
2092 | 2095 | ||
2093 | if (changed & BSS_CHANGED_ERP_SLOT) { | 2096 | if (changed & BSS_CHANGED_ERP_SLOT) { |
2094 | if (bss_conf->use_short_slot) | 2097 | if (bss_conf->use_short_slot) |
2095 | slottime = 9; | 2098 | slottime = 9; |
2096 | else | 2099 | else |
2097 | slottime = 20; | 2100 | slottime = 20; |
2098 | if (vif->type == NL80211_IFTYPE_AP) { | 2101 | if (vif->type == NL80211_IFTYPE_AP) { |
2099 | /* | 2102 | /* |
2100 | * Defer update, so that connected stations can adjust | 2103 | * Defer update, so that connected stations can adjust |
2101 | * their settings at the same time. | 2104 | * their settings at the same time. |
2102 | * See beacon.c for more details | 2105 | * See beacon.c for more details |
2103 | */ | 2106 | */ |
2104 | sc->beacon.slottime = slottime; | 2107 | sc->beacon.slottime = slottime; |
2105 | sc->beacon.updateslot = UPDATE; | 2108 | sc->beacon.updateslot = UPDATE; |
2106 | } else { | 2109 | } else { |
2107 | ah->slottime = slottime; | 2110 | ah->slottime = slottime; |
2108 | ath9k_hw_init_global_settings(ah); | 2111 | ath9k_hw_init_global_settings(ah); |
2109 | } | 2112 | } |
2110 | } | 2113 | } |
2111 | 2114 | ||
2112 | /* Disable transmission of beacons */ | 2115 | /* Disable transmission of beacons */ |
2113 | if ((changed & BSS_CHANGED_BEACON_ENABLED) && | 2116 | if ((changed & BSS_CHANGED_BEACON_ENABLED) && |
2114 | !bss_conf->enable_beacon) { | 2117 | !bss_conf->enable_beacon) { |
2115 | ath9k_set_beaconing_status(sc, false); | 2118 | ath9k_set_beaconing_status(sc, false); |
2116 | avp->is_bslot_active = false; | 2119 | avp->is_bslot_active = false; |
2117 | ath9k_set_beaconing_status(sc, true); | 2120 | ath9k_set_beaconing_status(sc, true); |
2118 | } | 2121 | } |
2119 | 2122 | ||
2120 | if (changed & BSS_CHANGED_BEACON_INT) { | 2123 | if (changed & BSS_CHANGED_BEACON_INT) { |
2121 | /* | 2124 | /* |
2122 | * In case of AP mode, the HW TSF has to be reset | 2125 | * In case of AP mode, the HW TSF has to be reset |
2123 | * when the beacon interval changes. | 2126 | * when the beacon interval changes. |
2124 | */ | 2127 | */ |
2125 | if (vif->type == NL80211_IFTYPE_AP) { | 2128 | if (vif->type == NL80211_IFTYPE_AP) { |
2126 | sc->sc_flags |= SC_OP_TSF_RESET; | 2129 | sc->sc_flags |= SC_OP_TSF_RESET; |
2127 | ath9k_set_beaconing_status(sc, false); | 2130 | ath9k_set_beaconing_status(sc, false); |
2128 | error = ath_beacon_alloc(sc, vif); | 2131 | error = ath_beacon_alloc(sc, vif); |
2129 | if (!error) | 2132 | if (!error) |
2130 | ath_beacon_config(sc, vif); | 2133 | ath_beacon_config(sc, vif); |
2131 | ath9k_set_beaconing_status(sc, true); | 2134 | ath9k_set_beaconing_status(sc, true); |
2132 | } else | 2135 | } else |
2133 | ath_beacon_config(sc, vif); | 2136 | ath_beacon_config(sc, vif); |
2134 | } | 2137 | } |
2135 | 2138 | ||
2136 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | 2139 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { |
2137 | ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", | 2140 | ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", |
2138 | bss_conf->use_short_preamble); | 2141 | bss_conf->use_short_preamble); |
2139 | if (bss_conf->use_short_preamble) | 2142 | if (bss_conf->use_short_preamble) |
2140 | sc->sc_flags |= SC_OP_PREAMBLE_SHORT; | 2143 | sc->sc_flags |= SC_OP_PREAMBLE_SHORT; |
2141 | else | 2144 | else |
2142 | sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; | 2145 | sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; |
2143 | } | 2146 | } |
2144 | 2147 | ||
2145 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | 2148 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { |
2146 | ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", | 2149 | ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", |
2147 | bss_conf->use_cts_prot); | 2150 | bss_conf->use_cts_prot); |
2148 | if (bss_conf->use_cts_prot && | 2151 | if (bss_conf->use_cts_prot && |
2149 | hw->conf.channel->band != IEEE80211_BAND_5GHZ) | 2152 | hw->conf.channel->band != IEEE80211_BAND_5GHZ) |
2150 | sc->sc_flags |= SC_OP_PROTECT_ENABLE; | 2153 | sc->sc_flags |= SC_OP_PROTECT_ENABLE; |
2151 | else | 2154 | else |
2152 | sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; | 2155 | sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; |
2153 | } | 2156 | } |
2154 | 2157 | ||
2155 | mutex_unlock(&sc->mutex); | 2158 | mutex_unlock(&sc->mutex); |
2156 | ath9k_ps_restore(sc); | 2159 | ath9k_ps_restore(sc); |
2157 | } | 2160 | } |
2158 | 2161 | ||
2159 | static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | 2162 | static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
2160 | { | 2163 | { |
2161 | struct ath_softc *sc = hw->priv; | 2164 | struct ath_softc *sc = hw->priv; |
2162 | u64 tsf; | 2165 | u64 tsf; |
2163 | 2166 | ||
2164 | mutex_lock(&sc->mutex); | 2167 | mutex_lock(&sc->mutex); |
2165 | ath9k_ps_wakeup(sc); | 2168 | ath9k_ps_wakeup(sc); |
2166 | tsf = ath9k_hw_gettsf64(sc->sc_ah); | 2169 | tsf = ath9k_hw_gettsf64(sc->sc_ah); |
2167 | ath9k_ps_restore(sc); | 2170 | ath9k_ps_restore(sc); |
2168 | mutex_unlock(&sc->mutex); | 2171 | mutex_unlock(&sc->mutex); |
2169 | 2172 | ||
2170 | return tsf; | 2173 | return tsf; |
2171 | } | 2174 | } |
2172 | 2175 | ||
2173 | static void ath9k_set_tsf(struct ieee80211_hw *hw, | 2176 | static void ath9k_set_tsf(struct ieee80211_hw *hw, |
2174 | struct ieee80211_vif *vif, | 2177 | struct ieee80211_vif *vif, |
2175 | u64 tsf) | 2178 | u64 tsf) |
2176 | { | 2179 | { |
2177 | struct ath_softc *sc = hw->priv; | 2180 | struct ath_softc *sc = hw->priv; |
2178 | 2181 | ||
2179 | mutex_lock(&sc->mutex); | 2182 | mutex_lock(&sc->mutex); |
2180 | ath9k_ps_wakeup(sc); | 2183 | ath9k_ps_wakeup(sc); |
2181 | ath9k_hw_settsf64(sc->sc_ah, tsf); | 2184 | ath9k_hw_settsf64(sc->sc_ah, tsf); |
2182 | ath9k_ps_restore(sc); | 2185 | ath9k_ps_restore(sc); |
2183 | mutex_unlock(&sc->mutex); | 2186 | mutex_unlock(&sc->mutex); |
2184 | } | 2187 | } |
2185 | 2188 | ||
2186 | static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | 2189 | static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
2187 | { | 2190 | { |
2188 | struct ath_softc *sc = hw->priv; | 2191 | struct ath_softc *sc = hw->priv; |
2189 | 2192 | ||
2190 | mutex_lock(&sc->mutex); | 2193 | mutex_lock(&sc->mutex); |
2191 | 2194 | ||
2192 | ath9k_ps_wakeup(sc); | 2195 | ath9k_ps_wakeup(sc); |
2193 | ath9k_hw_reset_tsf(sc->sc_ah); | 2196 | ath9k_hw_reset_tsf(sc->sc_ah); |
2194 | ath9k_ps_restore(sc); | 2197 | ath9k_ps_restore(sc); |
2195 | 2198 | ||
2196 | mutex_unlock(&sc->mutex); | 2199 | mutex_unlock(&sc->mutex); |
2197 | } | 2200 | } |
2198 | 2201 | ||
2199 | static int ath9k_ampdu_action(struct ieee80211_hw *hw, | 2202 | static int ath9k_ampdu_action(struct ieee80211_hw *hw, |
2200 | struct ieee80211_vif *vif, | 2203 | struct ieee80211_vif *vif, |
2201 | enum ieee80211_ampdu_mlme_action action, | 2204 | enum ieee80211_ampdu_mlme_action action, |
2202 | struct ieee80211_sta *sta, | 2205 | struct ieee80211_sta *sta, |
2203 | u16 tid, u16 *ssn, u8 buf_size) | 2206 | u16 tid, u16 *ssn, u8 buf_size) |
2204 | { | 2207 | { |
2205 | struct ath_softc *sc = hw->priv; | 2208 | struct ath_softc *sc = hw->priv; |
2206 | int ret = 0; | 2209 | int ret = 0; |
2207 | 2210 | ||
2208 | local_bh_disable(); | 2211 | local_bh_disable(); |
2209 | 2212 | ||
2210 | switch (action) { | 2213 | switch (action) { |
2211 | case IEEE80211_AMPDU_RX_START: | 2214 | case IEEE80211_AMPDU_RX_START: |
2212 | if (!(sc->sc_flags & SC_OP_RXAGGR)) | 2215 | if (!(sc->sc_flags & SC_OP_RXAGGR)) |
2213 | ret = -ENOTSUPP; | 2216 | ret = -ENOTSUPP; |
2214 | break; | 2217 | break; |
2215 | case IEEE80211_AMPDU_RX_STOP: | 2218 | case IEEE80211_AMPDU_RX_STOP: |
2216 | break; | 2219 | break; |
2217 | case IEEE80211_AMPDU_TX_START: | 2220 | case IEEE80211_AMPDU_TX_START: |
2218 | if (!(sc->sc_flags & SC_OP_TXAGGR)) | 2221 | if (!(sc->sc_flags & SC_OP_TXAGGR)) |
2219 | return -EOPNOTSUPP; | 2222 | return -EOPNOTSUPP; |
2220 | 2223 | ||
2221 | ath9k_ps_wakeup(sc); | 2224 | ath9k_ps_wakeup(sc); |
2222 | ret = ath_tx_aggr_start(sc, sta, tid, ssn); | 2225 | ret = ath_tx_aggr_start(sc, sta, tid, ssn); |
2223 | if (!ret) | 2226 | if (!ret) |
2224 | ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); | 2227 | ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); |
2225 | ath9k_ps_restore(sc); | 2228 | ath9k_ps_restore(sc); |
2226 | break; | 2229 | break; |
2227 | case IEEE80211_AMPDU_TX_STOP: | 2230 | case IEEE80211_AMPDU_TX_STOP: |
2228 | ath9k_ps_wakeup(sc); | 2231 | ath9k_ps_wakeup(sc); |
2229 | ath_tx_aggr_stop(sc, sta, tid); | 2232 | ath_tx_aggr_stop(sc, sta, tid); |
2230 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | 2233 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); |
2231 | ath9k_ps_restore(sc); | 2234 | ath9k_ps_restore(sc); |
2232 | break; | 2235 | break; |
2233 | case IEEE80211_AMPDU_TX_OPERATIONAL: | 2236 | case IEEE80211_AMPDU_TX_OPERATIONAL: |
2234 | ath9k_ps_wakeup(sc); | 2237 | ath9k_ps_wakeup(sc); |
2235 | ath_tx_aggr_resume(sc, sta, tid); | 2238 | ath_tx_aggr_resume(sc, sta, tid); |
2236 | ath9k_ps_restore(sc); | 2239 | ath9k_ps_restore(sc); |
2237 | break; | 2240 | break; |
2238 | default: | 2241 | default: |
2239 | ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n"); | 2242 | ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n"); |
2240 | } | 2243 | } |
2241 | 2244 | ||
2242 | local_bh_enable(); | 2245 | local_bh_enable(); |
2243 | 2246 | ||
2244 | return ret; | 2247 | return ret; |
2245 | } | 2248 | } |
2246 | 2249 | ||
2247 | static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, | 2250 | static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, |
2248 | struct survey_info *survey) | 2251 | struct survey_info *survey) |
2249 | { | 2252 | { |
2250 | struct ath_softc *sc = hw->priv; | 2253 | struct ath_softc *sc = hw->priv; |
2251 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 2254 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
2252 | struct ieee80211_supported_band *sband; | 2255 | struct ieee80211_supported_band *sband; |
2253 | struct ieee80211_channel *chan; | 2256 | struct ieee80211_channel *chan; |
2254 | unsigned long flags; | 2257 | unsigned long flags; |
2255 | int pos; | 2258 | int pos; |
2256 | 2259 | ||
2257 | spin_lock_irqsave(&common->cc_lock, flags); | 2260 | spin_lock_irqsave(&common->cc_lock, flags); |
2258 | if (idx == 0) | 2261 | if (idx == 0) |
2259 | ath_update_survey_stats(sc); | 2262 | ath_update_survey_stats(sc); |
2260 | 2263 | ||
2261 | sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ]; | 2264 | sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ]; |
2262 | if (sband && idx >= sband->n_channels) { | 2265 | if (sband && idx >= sband->n_channels) { |
2263 | idx -= sband->n_channels; | 2266 | idx -= sband->n_channels; |
2264 | sband = NULL; | 2267 | sband = NULL; |
2265 | } | 2268 | } |
2266 | 2269 | ||
2267 | if (!sband) | 2270 | if (!sband) |
2268 | sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ]; | 2271 | sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ]; |
2269 | 2272 | ||
2270 | if (!sband || idx >= sband->n_channels) { | 2273 | if (!sband || idx >= sband->n_channels) { |
2271 | spin_unlock_irqrestore(&common->cc_lock, flags); | 2274 | spin_unlock_irqrestore(&common->cc_lock, flags); |
2272 | return -ENOENT; | 2275 | return -ENOENT; |
2273 | } | 2276 | } |
2274 | 2277 | ||
2275 | chan = &sband->channels[idx]; | 2278 | chan = &sband->channels[idx]; |
2276 | pos = chan->hw_value; | 2279 | pos = chan->hw_value; |
2277 | memcpy(survey, &sc->survey[pos], sizeof(*survey)); | 2280 | memcpy(survey, &sc->survey[pos], sizeof(*survey)); |
2278 | survey->channel = chan; | 2281 | survey->channel = chan; |
2279 | spin_unlock_irqrestore(&common->cc_lock, flags); | 2282 | spin_unlock_irqrestore(&common->cc_lock, flags); |
2280 | 2283 | ||
2281 | return 0; | 2284 | return 0; |
2282 | } | 2285 | } |
2283 | 2286 | ||
2284 | static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) | 2287 | static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) |
2285 | { | 2288 | { |
2286 | struct ath_softc *sc = hw->priv; | 2289 | struct ath_softc *sc = hw->priv; |
2287 | struct ath_hw *ah = sc->sc_ah; | 2290 | struct ath_hw *ah = sc->sc_ah; |
2288 | 2291 | ||
2289 | mutex_lock(&sc->mutex); | 2292 | mutex_lock(&sc->mutex); |
2290 | ah->coverage_class = coverage_class; | 2293 | ah->coverage_class = coverage_class; |
2291 | 2294 | ||
2292 | ath9k_ps_wakeup(sc); | 2295 | ath9k_ps_wakeup(sc); |
2293 | ath9k_hw_init_global_settings(ah); | 2296 | ath9k_hw_init_global_settings(ah); |
2294 | ath9k_ps_restore(sc); | 2297 | ath9k_ps_restore(sc); |
2295 | 2298 | ||
2296 | mutex_unlock(&sc->mutex); | 2299 | mutex_unlock(&sc->mutex); |
2297 | } | 2300 | } |
2298 | 2301 | ||
2299 | static void ath9k_flush(struct ieee80211_hw *hw, bool drop) | 2302 | static void ath9k_flush(struct ieee80211_hw *hw, bool drop) |
2300 | { | 2303 | { |
2301 | struct ath_softc *sc = hw->priv; | 2304 | struct ath_softc *sc = hw->priv; |
2302 | struct ath_hw *ah = sc->sc_ah; | 2305 | struct ath_hw *ah = sc->sc_ah; |
2303 | struct ath_common *common = ath9k_hw_common(ah); | 2306 | struct ath_common *common = ath9k_hw_common(ah); |
2304 | int timeout = 200; /* ms */ | 2307 | int timeout = 200; /* ms */ |
2305 | int i, j; | 2308 | int i, j; |
2306 | bool drain_txq; | 2309 | bool drain_txq; |
2307 | 2310 | ||
2308 | mutex_lock(&sc->mutex); | 2311 | mutex_lock(&sc->mutex); |
2309 | cancel_delayed_work_sync(&sc->tx_complete_work); | 2312 | cancel_delayed_work_sync(&sc->tx_complete_work); |
2310 | 2313 | ||
2311 | if (ah->ah_flags & AH_UNPLUGGED) { | 2314 | if (ah->ah_flags & AH_UNPLUGGED) { |
2312 | ath_dbg(common, ATH_DBG_ANY, "Device has been unplugged!\n"); | 2315 | ath_dbg(common, ATH_DBG_ANY, "Device has been unplugged!\n"); |
2313 | mutex_unlock(&sc->mutex); | 2316 | mutex_unlock(&sc->mutex); |
2314 | return; | 2317 | return; |
2315 | } | 2318 | } |
2316 | 2319 | ||
2317 | if (sc->sc_flags & SC_OP_INVALID) { | 2320 | if (sc->sc_flags & SC_OP_INVALID) { |
2318 | ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); | 2321 | ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); |
2319 | mutex_unlock(&sc->mutex); | 2322 | mutex_unlock(&sc->mutex); |
2320 | return; | 2323 | return; |
2321 | } | 2324 | } |
2322 | 2325 | ||
2323 | if (drop) | 2326 | if (drop) |
2324 | timeout = 1; | 2327 | timeout = 1; |
2325 | 2328 | ||
2326 | for (j = 0; j < timeout; j++) { | 2329 | for (j = 0; j < timeout; j++) { |
2327 | bool npend = false; | 2330 | bool npend = false; |
2328 | 2331 | ||
2329 | if (j) | 2332 | if (j) |
2330 | usleep_range(1000, 2000); | 2333 | usleep_range(1000, 2000); |
2331 | 2334 | ||
2332 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { | 2335 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { |
2333 | if (!ATH_TXQ_SETUP(sc, i)) | 2336 | if (!ATH_TXQ_SETUP(sc, i)) |
2334 | continue; | 2337 | continue; |
2335 | 2338 | ||
2336 | npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]); | 2339 | npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]); |
2337 | 2340 | ||
2338 | if (npend) | 2341 | if (npend) |
2339 | break; | 2342 | break; |
2340 | } | 2343 | } |
2341 | 2344 | ||
2342 | if (!npend) | 2345 | if (!npend) |
2343 | goto out; | 2346 | goto out; |
2344 | } | 2347 | } |
2345 | 2348 | ||
2346 | ath9k_ps_wakeup(sc); | 2349 | ath9k_ps_wakeup(sc); |
2347 | spin_lock_bh(&sc->sc_pcu_lock); | 2350 | spin_lock_bh(&sc->sc_pcu_lock); |
2348 | drain_txq = ath_drain_all_txq(sc, false); | 2351 | drain_txq = ath_drain_all_txq(sc, false); |
2349 | spin_unlock_bh(&sc->sc_pcu_lock); | 2352 | spin_unlock_bh(&sc->sc_pcu_lock); |
2350 | 2353 | ||
2351 | if (!drain_txq) | 2354 | if (!drain_txq) |
2352 | ath_reset(sc, false); | 2355 | ath_reset(sc, false); |
2353 | 2356 | ||
2354 | ath9k_ps_restore(sc); | 2357 | ath9k_ps_restore(sc); |
2355 | ieee80211_wake_queues(hw); | 2358 | ieee80211_wake_queues(hw); |
2356 | 2359 | ||
2357 | out: | 2360 | out: |
2358 | ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); | 2361 | ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); |
2359 | mutex_unlock(&sc->mutex); | 2362 | mutex_unlock(&sc->mutex); |
2360 | } | 2363 | } |
2361 | 2364 | ||
2362 | static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) | 2365 | static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) |
2363 | { | 2366 | { |
2364 | struct ath_softc *sc = hw->priv; | 2367 | struct ath_softc *sc = hw->priv; |
2365 | int i; | 2368 | int i; |
2366 | 2369 | ||
2367 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { | 2370 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { |
2368 | if (!ATH_TXQ_SETUP(sc, i)) | 2371 | if (!ATH_TXQ_SETUP(sc, i)) |
2369 | continue; | 2372 | continue; |
2370 | 2373 | ||
2371 | if (ath9k_has_pending_frames(sc, &sc->tx.txq[i])) | 2374 | if (ath9k_has_pending_frames(sc, &sc->tx.txq[i])) |
2372 | return true; | 2375 | return true; |
2373 | } | 2376 | } |
2374 | return false; | 2377 | return false; |
2375 | } | 2378 | } |
2376 | 2379 | ||
2377 | static int ath9k_tx_last_beacon(struct ieee80211_hw *hw) | 2380 | static int ath9k_tx_last_beacon(struct ieee80211_hw *hw) |
2378 | { | 2381 | { |
2379 | struct ath_softc *sc = hw->priv; | 2382 | struct ath_softc *sc = hw->priv; |
2380 | struct ath_hw *ah = sc->sc_ah; | 2383 | struct ath_hw *ah = sc->sc_ah; |
2381 | struct ieee80211_vif *vif; | 2384 | struct ieee80211_vif *vif; |
2382 | struct ath_vif *avp; | 2385 | struct ath_vif *avp; |
2383 | struct ath_buf *bf; | 2386 | struct ath_buf *bf; |
2384 | struct ath_tx_status ts; | 2387 | struct ath_tx_status ts; |
2385 | int status; | 2388 | int status; |
2386 | 2389 | ||
2387 | vif = sc->beacon.bslot[0]; | 2390 | vif = sc->beacon.bslot[0]; |
2388 | if (!vif) | 2391 | if (!vif) |
2389 | return 0; | 2392 | return 0; |
2390 | 2393 | ||
2391 | avp = (void *)vif->drv_priv; | 2394 | avp = (void *)vif->drv_priv; |
2392 | if (!avp->is_bslot_active) | 2395 | if (!avp->is_bslot_active) |
2393 | return 0; | 2396 | return 0; |
2394 | 2397 | ||
2395 | if (!sc->beacon.tx_processed) { | 2398 | if (!sc->beacon.tx_processed) { |
2396 | tasklet_disable(&sc->bcon_tasklet); | 2399 | tasklet_disable(&sc->bcon_tasklet); |
2397 | 2400 | ||
2398 | bf = avp->av_bcbuf; | 2401 | bf = avp->av_bcbuf; |
2399 | if (!bf || !bf->bf_mpdu) | 2402 | if (!bf || !bf->bf_mpdu) |
2400 | goto skip; | 2403 | goto skip; |
2401 | 2404 | ||
2402 | status = ath9k_hw_txprocdesc(ah, bf->bf_desc, &ts); | 2405 | status = ath9k_hw_txprocdesc(ah, bf->bf_desc, &ts); |
2403 | if (status == -EINPROGRESS) | 2406 | if (status == -EINPROGRESS) |
2404 | goto skip; | 2407 | goto skip; |
2405 | 2408 | ||
2406 | sc->beacon.tx_processed = true; | 2409 | sc->beacon.tx_processed = true; |
2407 | sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); | 2410 | sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); |
2408 | 2411 | ||
2409 | skip: | 2412 | skip: |
2410 | tasklet_enable(&sc->bcon_tasklet); | 2413 | tasklet_enable(&sc->bcon_tasklet); |
2411 | } | 2414 | } |
2412 | 2415 | ||
2413 | return sc->beacon.tx_last; | 2416 | return sc->beacon.tx_last; |
2414 | } | 2417 | } |
2415 | 2418 | ||
2416 | static int ath9k_get_stats(struct ieee80211_hw *hw, | 2419 | static int ath9k_get_stats(struct ieee80211_hw *hw, |
2417 | struct ieee80211_low_level_stats *stats) | 2420 | struct ieee80211_low_level_stats *stats) |
2418 | { | 2421 | { |
2419 | struct ath_softc *sc = hw->priv; | 2422 | struct ath_softc *sc = hw->priv; |
2420 | struct ath_hw *ah = sc->sc_ah; | 2423 | struct ath_hw *ah = sc->sc_ah; |
2421 | struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats; | 2424 | struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats; |
2422 | 2425 | ||
2423 | stats->dot11ACKFailureCount = mib_stats->ackrcv_bad; | 2426 | stats->dot11ACKFailureCount = mib_stats->ackrcv_bad; |
2424 | stats->dot11RTSFailureCount = mib_stats->rts_bad; | 2427 | stats->dot11RTSFailureCount = mib_stats->rts_bad; |
2425 | stats->dot11FCSErrorCount = mib_stats->fcs_bad; | 2428 | stats->dot11FCSErrorCount = mib_stats->fcs_bad; |
2426 | stats->dot11RTSSuccessCount = mib_stats->rts_good; | 2429 | stats->dot11RTSSuccessCount = mib_stats->rts_good; |
2427 | return 0; | 2430 | return 0; |
2428 | } | 2431 | } |
2429 | 2432 | ||
2430 | static u32 fill_chainmask(u32 cap, u32 new) | 2433 | static u32 fill_chainmask(u32 cap, u32 new) |
2431 | { | 2434 | { |
2432 | u32 filled = 0; | 2435 | u32 filled = 0; |
2433 | int i; | 2436 | int i; |
2434 | 2437 | ||
2435 | for (i = 0; cap && new; i++, cap >>= 1) { | 2438 | for (i = 0; cap && new; i++, cap >>= 1) { |
2436 | if (!(cap & BIT(0))) | 2439 | if (!(cap & BIT(0))) |
2437 | continue; | 2440 | continue; |
2438 | 2441 | ||
2439 | if (new & BIT(0)) | 2442 | if (new & BIT(0)) |
2440 | filled |= BIT(i); | 2443 | filled |= BIT(i); |
2441 | 2444 | ||
2442 | new >>= 1; | 2445 | new >>= 1; |
2443 | } | 2446 | } |
2444 | 2447 | ||
2445 | return filled; | 2448 | return filled; |
2446 | } | 2449 | } |
2447 | 2450 | ||
2448 | static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) | 2451 | static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) |
2449 | { | 2452 | { |
2450 | struct ath_softc *sc = hw->priv; | 2453 | struct ath_softc *sc = hw->priv; |
2451 | struct ath_hw *ah = sc->sc_ah; | 2454 | struct ath_hw *ah = sc->sc_ah; |
2452 | 2455 | ||
2453 | if (!rx_ant || !tx_ant) | 2456 | if (!rx_ant || !tx_ant) |
2454 | return -EINVAL; | 2457 | return -EINVAL; |
2455 | 2458 | ||
2456 | sc->ant_rx = rx_ant; | 2459 | sc->ant_rx = rx_ant; |
2457 | sc->ant_tx = tx_ant; | 2460 | sc->ant_tx = tx_ant; |
2458 | 2461 | ||
2459 | if (ah->caps.rx_chainmask == 1) | 2462 | if (ah->caps.rx_chainmask == 1) |
2460 | return 0; | 2463 | return 0; |
2461 | 2464 | ||
2462 | /* AR9100 runs into calibration issues if not all rx chains are enabled */ | 2465 | /* AR9100 runs into calibration issues if not all rx chains are enabled */ |
2463 | if (AR_SREV_9100(ah)) | 2466 | if (AR_SREV_9100(ah)) |
2464 | ah->rxchainmask = 0x7; | 2467 | ah->rxchainmask = 0x7; |
2465 | else | 2468 | else |
2466 | ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant); | 2469 | ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant); |
2467 | 2470 | ||
2468 | ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant); | 2471 | ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant); |
2469 | ath9k_reload_chainmask_settings(sc); | 2472 | ath9k_reload_chainmask_settings(sc); |
2470 | 2473 | ||
2471 | return 0; | 2474 | return 0; |
2472 | } | 2475 | } |
2473 | 2476 | ||
2474 | static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) | 2477 | static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) |
2475 | { | 2478 | { |
2476 | struct ath_softc *sc = hw->priv; | 2479 | struct ath_softc *sc = hw->priv; |
2477 | 2480 | ||
2478 | *tx_ant = sc->ant_tx; | 2481 | *tx_ant = sc->ant_tx; |
2479 | *rx_ant = sc->ant_rx; | 2482 | *rx_ant = sc->ant_rx; |
2480 | return 0; | 2483 | return 0; |
2481 | } | 2484 | } |
2482 | 2485 | ||
2483 | struct ieee80211_ops ath9k_ops = { | 2486 | struct ieee80211_ops ath9k_ops = { |
2484 | .tx = ath9k_tx, | 2487 | .tx = ath9k_tx, |
2485 | .start = ath9k_start, | 2488 | .start = ath9k_start, |
2486 | .stop = ath9k_stop, | 2489 | .stop = ath9k_stop, |
2487 | .add_interface = ath9k_add_interface, | 2490 | .add_interface = ath9k_add_interface, |
2488 | .change_interface = ath9k_change_interface, | 2491 | .change_interface = ath9k_change_interface, |
2489 | .remove_interface = ath9k_remove_interface, | 2492 | .remove_interface = ath9k_remove_interface, |
2490 | .config = ath9k_config, | 2493 | .config = ath9k_config, |
2491 | .configure_filter = ath9k_configure_filter, | 2494 | .configure_filter = ath9k_configure_filter, |
2492 | .sta_add = ath9k_sta_add, | 2495 | .sta_add = ath9k_sta_add, |
2493 | .sta_remove = ath9k_sta_remove, | 2496 | .sta_remove = ath9k_sta_remove, |
2494 | .sta_notify = ath9k_sta_notify, | 2497 | .sta_notify = ath9k_sta_notify, |
2495 | .conf_tx = ath9k_conf_tx, | 2498 | .conf_tx = ath9k_conf_tx, |
2496 | .bss_info_changed = ath9k_bss_info_changed, | 2499 | .bss_info_changed = ath9k_bss_info_changed, |
2497 | .set_key = ath9k_set_key, | 2500 | .set_key = ath9k_set_key, |
2498 | .get_tsf = ath9k_get_tsf, | 2501 | .get_tsf = ath9k_get_tsf, |
2499 | .set_tsf = ath9k_set_tsf, | 2502 | .set_tsf = ath9k_set_tsf, |
2500 | .reset_tsf = ath9k_reset_tsf, | 2503 | .reset_tsf = ath9k_reset_tsf, |
2501 | .ampdu_action = ath9k_ampdu_action, | 2504 | .ampdu_action = ath9k_ampdu_action, |
2502 | .get_survey = ath9k_get_survey, | 2505 | .get_survey = ath9k_get_survey, |
2503 | .rfkill_poll = ath9k_rfkill_poll_state, | 2506 | .rfkill_poll = ath9k_rfkill_poll_state, |
2504 | .set_coverage_class = ath9k_set_coverage_class, | 2507 | .set_coverage_class = ath9k_set_coverage_class, |
2505 | .flush = ath9k_flush, | 2508 | .flush = ath9k_flush, |
2506 | .tx_frames_pending = ath9k_tx_frames_pending, | 2509 | .tx_frames_pending = ath9k_tx_frames_pending, |
2507 | .tx_last_beacon = ath9k_tx_last_beacon, | 2510 | .tx_last_beacon = ath9k_tx_last_beacon, |
2508 | .get_stats = ath9k_get_stats, | 2511 | .get_stats = ath9k_get_stats, |
2509 | .set_antenna = ath9k_set_antenna, | 2512 | .set_antenna = ath9k_set_antenna, |
2510 | .get_antenna = ath9k_get_antenna, | 2513 | .get_antenna = ath9k_get_antenna, |
2511 | }; | 2514 | }; |
2512 | 2515 |