blob: 7e518aad37eadf2937ba4ba762b8273d429bfa30 [file] [log] [blame]
Felix Fietkaufbbcd142014-06-11 16:17:49 +05301/*
2 * Copyright (c) 2014 Qualcomm Atheros, Inc.
3 *
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
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
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
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "ath9k.h"
18
19/* Set/change channels. If the channel is really being changed, it's done
20 * by reseting the chip. To accomplish this we must first cleanup any pending
21 * DMA, then restart stuff.
22 */
23static int ath_set_channel(struct ath_softc *sc)
24{
25 struct ath_hw *ah = sc->sc_ah;
26 struct ath_common *common = ath9k_hw_common(ah);
27 struct ieee80211_hw *hw = sc->hw;
28 struct ath9k_channel *hchan;
29 struct cfg80211_chan_def *chandef = &sc->cur_chan->chandef;
30 struct ieee80211_channel *chan = chandef->chan;
31 int pos = chan->hw_value;
32 int old_pos = -1;
33 int r;
34
35 if (test_bit(ATH_OP_INVALID, &common->op_flags))
36 return -EIO;
37
38 if (ah->curchan)
39 old_pos = ah->curchan - &ah->channels[0];
40
41 ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n",
42 chan->center_freq, chandef->width);
43
44 /* update survey stats for the old channel before switching */
45 spin_lock_bh(&common->cc_lock);
46 ath_update_survey_stats(sc);
47 spin_unlock_bh(&common->cc_lock);
48
49 ath9k_cmn_get_channel(hw, ah, chandef);
50
51 /* If the operating channel changes, change the survey in-use flags
52 * along with it.
53 * Reset the survey data for the new channel, unless we're switching
54 * back to the operating channel from an off-channel operation.
55 */
56 if (!sc->cur_chan->offchannel && sc->cur_survey != &sc->survey[pos]) {
57 if (sc->cur_survey)
58 sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE;
59
60 sc->cur_survey = &sc->survey[pos];
61
62 memset(sc->cur_survey, 0, sizeof(struct survey_info));
63 sc->cur_survey->filled |= SURVEY_INFO_IN_USE;
64 } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) {
65 memset(&sc->survey[pos], 0, sizeof(struct survey_info));
66 }
67
68 hchan = &sc->sc_ah->channels[pos];
Sujith Manoharan5555c952014-10-17 07:40:11 +053069 r = ath_reset(sc, hchan);
Felix Fietkaufbbcd142014-06-11 16:17:49 +053070 if (r)
71 return r;
72
73 /* The most recent snapshot of channel->noisefloor for the old
74 * channel is only available after the hardware reset. Copy it to
75 * the survey stats now.
76 */
77 if (old_pos >= 0)
78 ath_update_survey_nf(sc, old_pos);
79
80 /* Enable radar pulse detection if on a DFS channel. Spectral
81 * scanning and radar detection can not be used concurrently.
82 */
83 if (hw->conf.radar_enabled) {
84 u32 rxfilter;
85
Felix Fietkaufbbcd142014-06-11 16:17:49 +053086 rxfilter = ath9k_hw_getrxfilter(ah);
87 rxfilter |= ATH9K_RX_FILTER_PHYRADAR |
88 ATH9K_RX_FILTER_PHYERR;
89 ath9k_hw_setrxfilter(ah, rxfilter);
90 ath_dbg(common, DFS, "DFS enabled at freq %d\n",
91 chan->center_freq);
92 } else {
93 /* perform spectral scan if requested. */
94 if (test_bit(ATH_OP_SCANNING, &common->op_flags) &&
95 sc->spectral_mode == SPECTRAL_CHANSCAN)
96 ath9k_spectral_scan_trigger(hw);
97 }
98
99 return 0;
100}
101
102void ath_chanctx_init(struct ath_softc *sc)
103{
104 struct ath_chanctx *ctx;
105 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
106 struct ieee80211_supported_band *sband;
107 struct ieee80211_channel *chan;
Felix Fietkau04535312014-06-11 16:17:51 +0530108 int i, j;
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530109
110 sband = &common->sbands[IEEE80211_BAND_2GHZ];
111 if (!sband->n_channels)
112 sband = &common->sbands[IEEE80211_BAND_5GHZ];
113
114 chan = &sband->channels[0];
115 for (i = 0; i < ATH9K_NUM_CHANCTX; i++) {
116 ctx = &sc->chanctx[i];
117 cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
118 INIT_LIST_HEAD(&ctx->vifs);
Felix Fietkaubc7e1be2014-06-11 16:17:50 +0530119 ctx->txpower = ATH_TXPOWER_MAX;
Sujith Manoharan2fae0d92014-10-17 07:40:15 +0530120 ctx->flush_timeout = HZ / 5; /* 200ms */
Felix Fietkau04535312014-06-11 16:17:51 +0530121 for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
122 INIT_LIST_HEAD(&ctx->acq[j]);
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530123 }
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530124}
125
Felix Fietkaubff11762014-06-11 16:17:52 +0530126void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
127 struct cfg80211_chan_def *chandef)
128{
Sujith Manoharan4c7e9ae2014-08-24 21:16:13 +0530129 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkaubff11762014-06-11 16:17:52 +0530130 bool cur_chan;
131
132 spin_lock_bh(&sc->chan_lock);
133 if (chandef)
134 memcpy(&ctx->chandef, chandef, sizeof(*chandef));
135 cur_chan = sc->cur_chan == ctx;
136 spin_unlock_bh(&sc->chan_lock);
137
Sujith Manoharan4c7e9ae2014-08-24 21:16:13 +0530138 if (!cur_chan) {
139 ath_dbg(common, CHAN_CTX,
140 "Current context differs from the new context\n");
Felix Fietkaubff11762014-06-11 16:17:52 +0530141 return;
Sujith Manoharan4c7e9ae2014-08-24 21:16:13 +0530142 }
Felix Fietkaubff11762014-06-11 16:17:52 +0530143
144 ath_set_channel(sc);
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530145}
Felix Fietkau78b21942014-06-11 16:17:55 +0530146
Sujith Manoharan27babf92014-08-23 13:29:16 +0530147#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
148
Sujith Manoharan0e08b5f2014-08-23 13:29:19 +0530149/**********************************************************/
150/* Functions to handle the channel context state machine. */
151/**********************************************************/
152
Sujith Manoharan27babf92014-08-23 13:29:16 +0530153static const char *offchannel_state_string(enum ath_offchannel_state state)
154{
Sujith Manoharan27babf92014-08-23 13:29:16 +0530155 switch (state) {
156 case_rtn_string(ATH_OFFCHANNEL_IDLE);
157 case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND);
158 case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT);
159 case_rtn_string(ATH_OFFCHANNEL_SUSPEND);
160 case_rtn_string(ATH_OFFCHANNEL_ROC_START);
161 case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT);
162 case_rtn_string(ATH_OFFCHANNEL_ROC_DONE);
163 default:
164 return "unknown";
165 }
166}
167
Sujith Manoharan5a8cbec2014-08-24 21:16:11 +0530168static const char *chanctx_event_string(enum ath_chanctx_event ev)
169{
170 switch (ev) {
171 case_rtn_string(ATH_CHANCTX_EVENT_BEACON_PREPARE);
172 case_rtn_string(ATH_CHANCTX_EVENT_BEACON_SENT);
173 case_rtn_string(ATH_CHANCTX_EVENT_TSF_TIMER);
174 case_rtn_string(ATH_CHANCTX_EVENT_BEACON_RECEIVED);
Sujith Manoharanb8f92792014-10-17 07:40:09 +0530175 case_rtn_string(ATH_CHANCTX_EVENT_AUTHORIZED);
Sujith Manoharan5a8cbec2014-08-24 21:16:11 +0530176 case_rtn_string(ATH_CHANCTX_EVENT_SWITCH);
177 case_rtn_string(ATH_CHANCTX_EVENT_ASSIGN);
178 case_rtn_string(ATH_CHANCTX_EVENT_UNASSIGN);
179 case_rtn_string(ATH_CHANCTX_EVENT_CHANGE);
180 case_rtn_string(ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
181 default:
182 return "unknown";
183 }
184}
185
186static const char *chanctx_state_string(enum ath_chanctx_state state)
187{
188 switch (state) {
189 case_rtn_string(ATH_CHANCTX_STATE_IDLE);
190 case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_BEACON);
191 case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_TIMER);
192 case_rtn_string(ATH_CHANCTX_STATE_SWITCH);
193 case_rtn_string(ATH_CHANCTX_STATE_FORCE_ACTIVE);
194 default:
195 return "unknown";
196 }
197}
198
Sujith Manoharana09798f2014-08-23 13:29:21 +0530199void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
200{
201 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith Manoharan67259d52014-10-17 07:40:16 +0530202 struct ath_chanctx *ictx;
Sujith Manoharana09798f2014-08-23 13:29:21 +0530203 struct ath_vif *avp;
204 bool active = false;
205 u8 n_active = 0;
206
207 if (!ctx)
208 return;
209
Sujith Manoharan67259d52014-10-17 07:40:16 +0530210 ictx = ctx;
211
Sujith Manoharana09798f2014-08-23 13:29:21 +0530212 list_for_each_entry(avp, &ctx->vifs, list) {
213 struct ieee80211_vif *vif = avp->vif;
214
215 switch (vif->type) {
216 case NL80211_IFTYPE_P2P_CLIENT:
217 case NL80211_IFTYPE_STATION:
Sujith Manoharancb355822014-09-17 14:45:56 +0530218 if (avp->assoc)
Sujith Manoharana09798f2014-08-23 13:29:21 +0530219 active = true;
220 break;
221 default:
222 active = true;
223 break;
224 }
225 }
226 ctx->active = active;
227
228 ath_for_each_chanctx(sc, ctx) {
229 if (!ctx->assigned || list_empty(&ctx->vifs))
230 continue;
231 n_active++;
232 }
233
Sujith Manoharan67259d52014-10-17 07:40:16 +0530234 spin_lock_bh(&sc->chan_lock);
235
Sujith Manoharana09798f2014-08-23 13:29:21 +0530236 if (n_active <= 1) {
Sujith Manoharan67259d52014-10-17 07:40:16 +0530237 ictx->flush_timeout = HZ / 5;
Sujith Manoharana09798f2014-08-23 13:29:21 +0530238 clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags);
Sujith Manoharan67259d52014-10-17 07:40:16 +0530239 spin_unlock_bh(&sc->chan_lock);
Sujith Manoharana09798f2014-08-23 13:29:21 +0530240 return;
241 }
Sujith Manoharan67259d52014-10-17 07:40:16 +0530242
243 ictx->flush_timeout = usecs_to_jiffies(sc->sched.channel_switch_time);
244
245 if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) {
246 spin_unlock_bh(&sc->chan_lock);
Sujith Manoharana09798f2014-08-23 13:29:21 +0530247 return;
Sujith Manoharan67259d52014-10-17 07:40:16 +0530248 }
249
250 spin_unlock_bh(&sc->chan_lock);
Sujith Manoharana09798f2014-08-23 13:29:21 +0530251
252 if (ath9k_is_chanctx_enabled()) {
253 ath_chanctx_event(sc, NULL,
254 ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
255 }
256}
257
Felix Fietkau58b57372014-06-11 16:18:08 +0530258static struct ath_chanctx *
259ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx)
260{
261 int idx = ctx - &sc->chanctx[0];
262
263 return &sc->chanctx[!idx];
264}
265
266static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc)
267{
268 struct ath_chanctx *prev, *cur;
269 struct timespec ts;
270 u32 cur_tsf, prev_tsf, beacon_int;
271 s32 offset;
272
273 beacon_int = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
274
275 cur = sc->cur_chan;
276 prev = ath_chanctx_get_next(sc, cur);
277
Sujith Manoharan7f30eac2014-09-15 11:25:51 +0530278 if (!prev->switch_after_beacon)
279 return;
280
Felix Fietkau58b57372014-06-11 16:18:08 +0530281 getrawmonotonic(&ts);
282 cur_tsf = (u32) cur->tsf_val +
283 ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts);
284
285 prev_tsf = prev->last_beacon - (u32) prev->tsf_val + cur_tsf;
286 prev_tsf -= ath9k_hw_get_tsf_offset(&prev->tsf_ts, &ts);
287
288 /* Adjust the TSF time of the AP chanctx to keep its beacons
289 * at half beacon interval offset relative to the STA chanctx.
290 */
291 offset = cur_tsf - prev_tsf;
292
293 /* Ignore stale data or spurious timestamps */
294 if (offset < 0 || offset > 3 * beacon_int)
295 return;
296
297 offset = beacon_int / 2 - (offset % beacon_int);
298 prev->tsf_val += offset;
299}
300
Felix Fietkau42eda112014-06-11 16:18:14 +0530301/* Configure the TSF based hardware timer for a channel switch.
302 * Also set up backup software timer, in case the gen timer fails.
303 * This could be caused by a hardware reset.
304 */
305static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
306{
Sujith Manoharan878066e2014-08-27 12:07:24 +0530307 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau42eda112014-06-11 16:18:14 +0530308 struct ath_hw *ah = sc->sc_ah;
309
310 ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000);
311 tsf_time -= ath9k_hw_gettsf32(ah);
312 tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1;
Sujith Manoharan1a7c5b72014-08-27 12:07:25 +0530313 mod_timer(&sc->sched.timer, jiffies + tsf_time);
Sujith Manoharan878066e2014-08-27 12:07:24 +0530314
315 ath_dbg(common, CHAN_CTX,
316 "Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time));
Felix Fietkau42eda112014-06-11 16:18:14 +0530317}
318
Felix Fietkau748299f2014-06-11 16:18:04 +0530319void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
320 enum ath_chanctx_event ev)
321{
322 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau58b57372014-06-11 16:18:08 +0530323 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkau74148632014-06-11 16:18:11 +0530324 struct ath_beacon_config *cur_conf;
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530325 struct ath_vif *avp = NULL;
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530326 struct ath_chanctx *ctx;
Felix Fietkau748299f2014-06-11 16:18:04 +0530327 u32 tsf_time;
Felix Fietkauec70abe2014-06-11 16:18:12 +0530328 u32 beacon_int;
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530329
330 if (vif)
331 avp = (struct ath_vif *) vif->drv_priv;
Felix Fietkau748299f2014-06-11 16:18:04 +0530332
333 spin_lock_bh(&sc->chan_lock);
334
Sujith Manoharan878066e2014-08-27 12:07:24 +0530335 ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s\n",
336 sc->cur_chan->chandef.center_freq1,
337 chanctx_event_string(ev),
338 chanctx_state_string(sc->sched.state));
339
Felix Fietkau748299f2014-06-11 16:18:04 +0530340 switch (ev) {
341 case ATH_CHANCTX_EVENT_BEACON_PREPARE:
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530342 if (avp->offchannel_duration)
343 avp->offchannel_duration = 0;
344
Sujith Manoharan878066e2014-08-27 12:07:24 +0530345 if (avp->chanctx != sc->cur_chan) {
346 ath_dbg(common, CHAN_CTX,
347 "Contexts differ, not preparing beacon\n");
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530348 break;
Sujith Manoharan878066e2014-08-27 12:07:24 +0530349 }
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530350
Sujith Manoharan367b3412014-09-05 09:50:57 +0530351 if (sc->sched.offchannel_pending && !sc->sched.wait_switch) {
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530352 sc->sched.offchannel_pending = false;
353 sc->next_chan = &sc->offchannel.chan;
354 sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
Sujith Manoharan878066e2014-08-27 12:07:24 +0530355 ath_dbg(common, CHAN_CTX,
356 "Setting offchannel_pending to false\n");
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530357 }
358
359 ctx = ath_chanctx_get_next(sc, sc->cur_chan);
360 if (ctx->active && sc->sched.state == ATH_CHANCTX_STATE_IDLE) {
361 sc->next_chan = ctx;
362 sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
Sujith Manoharan878066e2014-08-27 12:07:24 +0530363 ath_dbg(common, CHAN_CTX,
364 "Set next context, move chanctx state to WAIT_FOR_BEACON\n");
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530365 }
366
367 /* if the timer missed its window, use the next interval */
Sujith Manoharan878066e2014-08-27 12:07:24 +0530368 if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER) {
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530369 sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
Sujith Manoharan878066e2014-08-27 12:07:24 +0530370 ath_dbg(common, CHAN_CTX,
371 "Move chanctx state from WAIT_FOR_TIMER to WAIT_FOR_BEACON\n");
372 }
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530373
Sujith Manoharan8890d052014-10-17 07:40:14 +0530374 /*
375 * When a context becomes inactive, for example,
376 * disassociation of a station context, the NoA
377 * attribute needs to be removed from subsequent
378 * beacons.
379 */
380 if (!ctx->active && avp->noa_duration &&
381 sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) {
382 avp->noa_duration = 0;
383 avp->periodic_noa = false;
384
385 ath_dbg(common, CHAN_CTX,
386 "Clearing NoA schedule\n");
387 }
388
Felix Fietkau748299f2014-06-11 16:18:04 +0530389 if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
390 break;
391
Sujith Manoharan878066e2014-08-27 12:07:24 +0530392 ath_dbg(common, CHAN_CTX, "Preparing beacon for vif: %pM\n", vif->addr);
393
Felix Fietkau748299f2014-06-11 16:18:04 +0530394 sc->sched.beacon_pending = true;
395 sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER);
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530396
Felix Fietkau74148632014-06-11 16:18:11 +0530397 cur_conf = &sc->cur_chan->beacon;
Felix Fietkauec70abe2014-06-11 16:18:12 +0530398 beacon_int = TU_TO_USEC(cur_conf->beacon_interval);
399
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530400 /* defer channel switch by a quarter beacon interval */
Felix Fietkauec70abe2014-06-11 16:18:12 +0530401 tsf_time = sc->sched.next_tbtt + beacon_int / 4;
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530402 sc->sched.switch_start_time = tsf_time;
Felix Fietkau58b57372014-06-11 16:18:08 +0530403 sc->cur_chan->last_beacon = sc->sched.next_tbtt;
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530404
Sujith Manoharand0975ed2014-09-10 19:15:57 +0530405 /*
406 * If an offchannel switch is scheduled to happen after
407 * a beacon transmission, update the NoA with one-shot
408 * values and increment the index.
409 */
410 if (sc->next_chan == &sc->offchannel.chan) {
411 avp->noa_index++;
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530412 avp->offchannel_start = tsf_time;
Sujith Manoharand0975ed2014-09-10 19:15:57 +0530413 avp->offchannel_duration = sc->sched.offchannel_duration;
414
415 ath_dbg(common, CHAN_CTX,
416 "offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
417 avp->offchannel_duration,
418 avp->offchannel_start,
419 avp->noa_index);
420
421 /*
422 * When multiple contexts are active, the NoA
423 * has to be recalculated and advertised after
424 * an offchannel operation.
425 */
426 if (ctx->active && avp->noa_duration)
427 avp->noa_duration = 0;
428
429 break;
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530430 }
431
Sujith Manoharan167bf96d2014-09-10 19:16:00 +0530432 /*
433 * Clear the extend_absence flag if it had been
434 * set during the previous beacon transmission,
435 * since we need to revert to the normal NoA
436 * schedule.
437 */
438 if (ctx->active && sc->sched.extend_absence) {
439 avp->noa_duration = 0;
440 sc->sched.extend_absence = false;
441 }
442
443 /* If at least two consecutive beacons were missed on the STA
444 * chanctx, stay on the STA channel for one extra beacon period,
445 * to resync the timer properly.
446 */
447 if (ctx->active && sc->sched.beacon_miss >= 2) {
448 avp->noa_duration = 0;
449 sc->sched.extend_absence = true;
450 }
Sujith Manoharana2b28602014-09-15 11:25:50 +0530451
Sujith Manoharand0975ed2014-09-10 19:15:57 +0530452 /* Prevent wrap-around issues */
453 if (avp->noa_duration && tsf_time - avp->noa_start > BIT(30))
454 avp->noa_duration = 0;
Sujith Manoharan878066e2014-08-27 12:07:24 +0530455
Sujith Manoharand0975ed2014-09-10 19:15:57 +0530456 /*
457 * If multiple contexts are active, start periodic
458 * NoA and increment the index for the first
459 * announcement.
460 */
461 if (ctx->active &&
462 (!avp->noa_duration || sc->sched.force_noa_update)) {
463 avp->noa_index++;
464 avp->noa_start = tsf_time;
Sujith Manoharand0975ed2014-09-10 19:15:57 +0530465
Sujith Manoharan167bf96d2014-09-10 19:16:00 +0530466 if (sc->sched.extend_absence)
467 avp->noa_duration = (3 * beacon_int / 2) +
468 sc->sched.channel_switch_time;
469 else
470 avp->noa_duration =
471 TU_TO_USEC(cur_conf->beacon_interval) / 2 +
472 sc->sched.channel_switch_time;
473
474 if (test_bit(ATH_OP_SCANNING, &common->op_flags) ||
475 sc->sched.extend_absence)
Sujith Manoharand0975ed2014-09-10 19:15:57 +0530476 avp->periodic_noa = false;
477 else
478 avp->periodic_noa = true;
479
480 ath_dbg(common, CHAN_CTX,
481 "noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
482 avp->noa_duration,
483 avp->noa_start,
484 avp->noa_index,
485 avp->periodic_noa);
486 }
487
488 if (ctx->active && sc->sched.force_noa_update)
489 sc->sched.force_noa_update = false;
Sujith Manoharan878066e2014-08-27 12:07:24 +0530490
Felix Fietkau748299f2014-06-11 16:18:04 +0530491 break;
492 case ATH_CHANCTX_EVENT_BEACON_SENT:
Sujith Manoharan878066e2014-08-27 12:07:24 +0530493 if (!sc->sched.beacon_pending) {
494 ath_dbg(common, CHAN_CTX,
495 "No pending beacon\n");
Felix Fietkau748299f2014-06-11 16:18:04 +0530496 break;
Sujith Manoharan878066e2014-08-27 12:07:24 +0530497 }
Felix Fietkau748299f2014-06-11 16:18:04 +0530498
499 sc->sched.beacon_pending = false;
500 if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
501 break;
502
Sujith Manoharan878066e2014-08-27 12:07:24 +0530503 ath_dbg(common, CHAN_CTX,
504 "Move chanctx state to WAIT_FOR_TIMER\n");
505
Felix Fietkau748299f2014-06-11 16:18:04 +0530506 sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
Felix Fietkau42eda112014-06-11 16:18:14 +0530507 ath_chanctx_setup_timer(sc, sc->sched.switch_start_time);
Felix Fietkau748299f2014-06-11 16:18:04 +0530508 break;
509 case ATH_CHANCTX_EVENT_TSF_TIMER:
510 if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_TIMER)
511 break;
512
Felix Fietkauec70abe2014-06-11 16:18:12 +0530513 if (!sc->cur_chan->switch_after_beacon &&
514 sc->sched.beacon_pending)
515 sc->sched.beacon_miss++;
516
Sujith Manoharan878066e2014-08-27 12:07:24 +0530517 ath_dbg(common, CHAN_CTX,
518 "Move chanctx state to SWITCH\n");
519
Felix Fietkau748299f2014-06-11 16:18:04 +0530520 sc->sched.state = ATH_CHANCTX_STATE_SWITCH;
521 ieee80211_queue_work(sc->hw, &sc->chanctx_work);
522 break;
Felix Fietkau58b57372014-06-11 16:18:08 +0530523 case ATH_CHANCTX_EVENT_BEACON_RECEIVED:
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530524 if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) ||
525 sc->cur_chan == &sc->offchannel.chan)
Felix Fietkau58b57372014-06-11 16:18:08 +0530526 break;
527
Felix Fietkauec70abe2014-06-11 16:18:12 +0530528 sc->sched.beacon_pending = false;
529 sc->sched.beacon_miss = 0;
Felix Fietkaua899b672014-06-11 16:18:13 +0530530
Sujith Manoharanbe247c12014-10-17 07:40:10 +0530531 if (sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE ||
532 !sc->cur_chan->tsf_val)
533 break;
534
535 ath_chanctx_adjust_tbtt_delta(sc);
536
Felix Fietkaua899b672014-06-11 16:18:13 +0530537 /* TSF time might have been updated by the incoming beacon,
538 * need update the channel switch timer to reflect the change.
539 */
540 tsf_time = sc->sched.switch_start_time;
541 tsf_time -= (u32) sc->cur_chan->tsf_val +
542 ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL);
543 tsf_time += ath9k_hw_gettsf32(ah);
544
Felix Fietkau42eda112014-06-11 16:18:14 +0530545
546 ath_chanctx_setup_timer(sc, tsf_time);
Felix Fietkau58b57372014-06-11 16:18:08 +0530547 break;
Sujith Manoharanb8f92792014-10-17 07:40:09 +0530548 case ATH_CHANCTX_EVENT_AUTHORIZED:
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530549 if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE ||
550 avp->chanctx != sc->cur_chan)
551 break;
552
Sujith Manoharan878066e2014-08-27 12:07:24 +0530553 ath_dbg(common, CHAN_CTX,
554 "Move chanctx state from FORCE_ACTIVE to IDLE\n");
555
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530556 sc->sched.state = ATH_CHANCTX_STATE_IDLE;
557 /* fall through */
558 case ATH_CHANCTX_EVENT_SWITCH:
559 if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) ||
560 sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE ||
561 sc->cur_chan->switch_after_beacon ||
562 sc->cur_chan == &sc->offchannel.chan)
563 break;
564
565 /* If this is a station chanctx, stay active for a half
566 * beacon period (minus channel switch time)
567 */
568 sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan);
Felix Fietkau74148632014-06-11 16:18:11 +0530569 cur_conf = &sc->cur_chan->beacon;
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530570
Sujith Manoharan878066e2014-08-27 12:07:24 +0530571 ath_dbg(common, CHAN_CTX,
572 "Move chanctx state to WAIT_FOR_TIMER (event SWITCH)\n");
573
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530574 sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
Sujith Manoharan367b3412014-09-05 09:50:57 +0530575 sc->sched.wait_switch = false;
Felix Fietkauec70abe2014-06-11 16:18:12 +0530576
577 tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2;
Sujith Manoharan167bf96d2014-09-10 19:16:00 +0530578
579 if (sc->sched.extend_absence) {
Felix Fietkauec70abe2014-06-11 16:18:12 +0530580 sc->sched.beacon_miss = 0;
581 tsf_time *= 3;
582 }
583
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530584 tsf_time -= sc->sched.channel_switch_time;
Felix Fietkauec70abe2014-06-11 16:18:12 +0530585 tsf_time += ath9k_hw_gettsf32(sc->sc_ah);
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530586 sc->sched.switch_start_time = tsf_time;
587
Felix Fietkau42eda112014-06-11 16:18:14 +0530588 ath_chanctx_setup_timer(sc, tsf_time);
Felix Fietkauec70abe2014-06-11 16:18:12 +0530589 sc->sched.beacon_pending = true;
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530590 break;
591 case ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL:
592 if (sc->cur_chan == &sc->offchannel.chan ||
593 sc->cur_chan->switch_after_beacon)
594 break;
595
596 sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan);
597 ieee80211_queue_work(sc->hw, &sc->chanctx_work);
598 break;
599 case ATH_CHANCTX_EVENT_UNASSIGN:
600 if (sc->cur_chan->assigned) {
601 if (sc->next_chan && !sc->next_chan->assigned &&
602 sc->next_chan != &sc->offchannel.chan)
603 sc->sched.state = ATH_CHANCTX_STATE_IDLE;
604 break;
605 }
606
607 ctx = ath_chanctx_get_next(sc, sc->cur_chan);
608 sc->sched.state = ATH_CHANCTX_STATE_IDLE;
609 if (!ctx->assigned)
610 break;
611
612 sc->next_chan = ctx;
613 ieee80211_queue_work(sc->hw, &sc->chanctx_work);
614 break;
Sujith Manoharan02da18b2014-08-24 21:16:10 +0530615 case ATH_CHANCTX_EVENT_ASSIGN:
Sujith Manoharan4c7e9ae2014-08-24 21:16:13 +0530616 /*
617 * When adding a new channel context, check if a scan
618 * is in progress and abort it since the addition of
619 * a new channel context is usually followed by VIF
620 * assignment, in which case we have to start multi-channel
621 * operation.
622 */
623 if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
624 ath_dbg(common, CHAN_CTX,
625 "Aborting HW scan to add new context\n");
626
627 spin_unlock_bh(&sc->chan_lock);
628 del_timer_sync(&sc->offchannel.timer);
629 ath_scan_complete(sc, true);
630 spin_lock_bh(&sc->chan_lock);
631 }
Sujith Manoharan02da18b2014-08-24 21:16:10 +0530632 break;
633 case ATH_CHANCTX_EVENT_CHANGE:
634 break;
Felix Fietkau748299f2014-06-11 16:18:04 +0530635 }
636
637 spin_unlock_bh(&sc->chan_lock);
638}
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530639
Sujith Manoharan70b06da2014-08-23 13:29:18 +0530640void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
641 enum ath_chanctx_event ev)
642{
643 if (sc->sched.beacon_pending)
644 ath_chanctx_event(sc, NULL, ev);
645}
646
Sujith Manoharana2b28602014-09-15 11:25:50 +0530647void ath_chanctx_beacon_recv_ev(struct ath_softc *sc,
Sujith Manoharan70b06da2014-08-23 13:29:18 +0530648 enum ath_chanctx_event ev)
649{
Sujith Manoharan70b06da2014-08-23 13:29:18 +0530650 ath_chanctx_event(sc, NULL, ev);
651}
652
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530653static int ath_scan_channel_duration(struct ath_softc *sc,
654 struct ieee80211_channel *chan)
655{
656 struct cfg80211_scan_request *req = sc->offchannel.scan_req;
657
658 if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR))
659 return (HZ / 9); /* ~110 ms */
660
661 return (HZ / 16); /* ~60 ms */
662}
663
Sujith Manoharan922c9432014-08-23 13:29:15 +0530664static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
665 struct cfg80211_chan_def *chandef)
666{
667 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
668
669 spin_lock_bh(&sc->chan_lock);
670
671 if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) &&
672 (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) {
Sujith Manoharanda0162f2014-09-05 09:50:56 +0530673 if (chandef)
674 ctx->chandef = *chandef;
Sujith Manoharancbc775d2014-09-10 19:15:56 +0530675
676 sc->sched.offchannel_pending = true;
677 sc->sched.wait_switch = true;
678 sc->sched.offchannel_duration =
679 jiffies_to_usecs(sc->offchannel.duration) +
680 sc->sched.channel_switch_time;
681
Sujith Manoharan922c9432014-08-23 13:29:15 +0530682 spin_unlock_bh(&sc->chan_lock);
Sujith Manoharanda0162f2014-09-05 09:50:56 +0530683 ath_dbg(common, CHAN_CTX,
684 "Set offchannel_pending to true\n");
Sujith Manoharan922c9432014-08-23 13:29:15 +0530685 return;
686 }
687
688 sc->next_chan = ctx;
689 if (chandef) {
690 ctx->chandef = *chandef;
691 ath_dbg(common, CHAN_CTX,
692 "Assigned next_chan to %d MHz\n", chandef->center_freq1);
693 }
694
695 if (sc->next_chan == &sc->offchannel.chan) {
696 sc->sched.offchannel_duration =
Sujith Manoharanbb628eb2014-09-05 08:03:13 +0530697 jiffies_to_usecs(sc->offchannel.duration) +
Sujith Manoharan922c9432014-08-23 13:29:15 +0530698 sc->sched.channel_switch_time;
699
700 if (chandef) {
701 ath_dbg(common, CHAN_CTX,
702 "Offchannel duration for chan %d MHz : %u\n",
703 chandef->center_freq1,
704 sc->sched.offchannel_duration);
705 }
706 }
707 spin_unlock_bh(&sc->chan_lock);
708 ieee80211_queue_work(sc->hw, &sc->chanctx_work);
709}
710
Sujith Manoharan344ae6a2014-08-23 13:29:13 +0530711static void ath_chanctx_offchan_switch(struct ath_softc *sc,
712 struct ieee80211_channel *chan)
713{
714 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
715 struct cfg80211_chan_def chandef;
716
717 cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
718 ath_dbg(common, CHAN_CTX,
719 "Channel definition created: %d MHz\n", chandef.center_freq1);
720
721 ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef);
722}
723
Sujith Manoharan98f411b2014-08-23 13:29:14 +0530724static struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc,
725 bool active)
726{
727 struct ath_chanctx *ctx;
728
729 ath_for_each_chanctx(sc, ctx) {
730 if (!ctx->assigned || list_empty(&ctx->vifs))
731 continue;
732 if (active && !ctx->active)
733 continue;
734
735 if (ctx->switch_after_beacon)
736 return ctx;
737 }
738
739 return &sc->chanctx[0];
740}
741
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530742static void
743ath_scan_next_channel(struct ath_softc *sc)
744{
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530745 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530746 struct cfg80211_scan_request *req = sc->offchannel.scan_req;
747 struct ieee80211_channel *chan;
748
749 if (sc->offchannel.scan_idx >= req->n_channels) {
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530750 ath_dbg(common, CHAN_CTX,
Sujith Manoharan878066e2014-08-27 12:07:24 +0530751 "Moving offchannel state to ATH_OFFCHANNEL_IDLE, "
752 "scan_idx: %d, n_channels: %d\n",
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530753 sc->offchannel.scan_idx,
754 req->n_channels);
755
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530756 sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
757 ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
758 NULL);
759 return;
760 }
761
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530762 ath_dbg(common, CHAN_CTX,
Sujith Manoharan878066e2014-08-27 12:07:24 +0530763 "Moving offchannel state to ATH_OFFCHANNEL_PROBE_SEND, scan_idx: %d\n",
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530764 sc->offchannel.scan_idx);
765
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530766 chan = req->channels[sc->offchannel.scan_idx++];
767 sc->offchannel.duration = ath_scan_channel_duration(sc, chan);
768 sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND;
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530769
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530770 ath_chanctx_offchan_switch(sc, chan);
771}
772
773void ath_offchannel_next(struct ath_softc *sc)
774{
775 struct ieee80211_vif *vif;
776
777 if (sc->offchannel.scan_req) {
778 vif = sc->offchannel.scan_vif;
779 sc->offchannel.chan.txpower = vif->bss_conf.txpower;
780 ath_scan_next_channel(sc);
781 } else if (sc->offchannel.roc_vif) {
782 vif = sc->offchannel.roc_vif;
783 sc->offchannel.chan.txpower = vif->bss_conf.txpower;
Sujith Manoharanbb628eb2014-09-05 08:03:13 +0530784 sc->offchannel.duration =
785 msecs_to_jiffies(sc->offchannel.roc_duration);
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530786 sc->offchannel.state = ATH_OFFCHANNEL_ROC_START;
787 ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan);
788 } else {
789 ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
790 NULL);
791 sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
792 if (sc->ps_idle)
793 ath_cancel_work(sc);
794 }
795}
796
797void ath_roc_complete(struct ath_softc *sc, bool abort)
798{
Sujith Manoharan4b60af42014-10-02 06:33:12 +0530799 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
800
801 if (abort)
802 ath_dbg(common, CHAN_CTX, "RoC aborted\n");
803 else
804 ath_dbg(common, CHAN_CTX, "RoC expired\n");
805
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530806 sc->offchannel.roc_vif = NULL;
807 sc->offchannel.roc_chan = NULL;
808 if (!abort)
809 ieee80211_remain_on_channel_expired(sc->hw);
810 ath_offchannel_next(sc);
811 ath9k_ps_restore(sc);
812}
813
814void ath_scan_complete(struct ath_softc *sc, bool abort)
815{
816 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
817
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530818 if (abort)
819 ath_dbg(common, CHAN_CTX, "HW scan aborted\n");
820 else
821 ath_dbg(common, CHAN_CTX, "HW scan complete\n");
822
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530823 sc->offchannel.scan_req = NULL;
824 sc->offchannel.scan_vif = NULL;
825 sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
826 ieee80211_scan_completed(sc->hw, abort);
827 clear_bit(ATH_OP_SCANNING, &common->op_flags);
Sujith Manoharand0975ed2014-09-10 19:15:57 +0530828 spin_lock_bh(&sc->chan_lock);
829 if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
830 sc->sched.force_noa_update = true;
831 spin_unlock_bh(&sc->chan_lock);
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530832 ath_offchannel_next(sc);
833 ath9k_ps_restore(sc);
834}
835
836static void ath_scan_send_probe(struct ath_softc *sc,
837 struct cfg80211_ssid *ssid)
838{
839 struct cfg80211_scan_request *req = sc->offchannel.scan_req;
840 struct ieee80211_vif *vif = sc->offchannel.scan_vif;
841 struct ath_tx_control txctl = {};
842 struct sk_buff *skb;
843 struct ieee80211_tx_info *info;
844 int band = sc->offchannel.chan.chandef.chan->band;
845
846 skb = ieee80211_probereq_get(sc->hw, vif,
847 ssid->ssid, ssid->ssid_len, req->ie_len);
848 if (!skb)
849 return;
850
851 info = IEEE80211_SKB_CB(skb);
852 if (req->no_cck)
853 info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
854
855 if (req->ie_len)
856 memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len);
857
858 skb_set_queue_mapping(skb, IEEE80211_AC_VO);
859
860 if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
861 goto error;
862
863 txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
864 txctl.force_channel = true;
865 if (ath_tx_start(sc->hw, skb, &txctl))
866 goto error;
867
868 return;
869
870error:
871 ieee80211_free_txskb(sc->hw, skb);
872}
873
874static void ath_scan_channel_start(struct ath_softc *sc)
875{
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530876 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530877 struct cfg80211_scan_request *req = sc->offchannel.scan_req;
878 int i;
879
880 if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) &&
881 req->n_ssids) {
882 for (i = 0; i < req->n_ssids; i++)
883 ath_scan_send_probe(sc, &req->ssids[i]);
884
885 }
886
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530887 ath_dbg(common, CHAN_CTX,
Sujith Manoharan878066e2014-08-27 12:07:24 +0530888 "Moving offchannel state to ATH_OFFCHANNEL_PROBE_WAIT\n");
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530889
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530890 sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT;
891 mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration);
892}
893
Sujith Manoharan705d0bf2014-08-23 13:29:06 +0530894static void ath_chanctx_timer(unsigned long data)
895{
896 struct ath_softc *sc = (struct ath_softc *) data;
Sujith Manoharan878066e2014-08-27 12:07:24 +0530897 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
898
899 ath_dbg(common, CHAN_CTX,
900 "Channel context timer invoked\n");
Sujith Manoharan705d0bf2014-08-23 13:29:06 +0530901
902 ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
903}
904
905static void ath_offchannel_timer(unsigned long data)
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530906{
907 struct ath_softc *sc = (struct ath_softc *)data;
908 struct ath_chanctx *ctx;
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530909 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
910
Sujith Manoharan878066e2014-08-27 12:07:24 +0530911 ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n",
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530912 __func__, offchannel_state_string(sc->offchannel.state));
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530913
914 switch (sc->offchannel.state) {
915 case ATH_OFFCHANNEL_PROBE_WAIT:
916 if (!sc->offchannel.scan_req)
917 return;
918
919 /* get first active channel context */
920 ctx = ath_chanctx_get_oper_chan(sc, true);
921 if (ctx->active) {
Sujith Manoharan878066e2014-08-27 12:07:24 +0530922 ath_dbg(common, CHAN_CTX,
923 "Switch to oper/active context, "
924 "move offchannel state to ATH_OFFCHANNEL_SUSPEND\n");
925
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530926 sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND;
927 ath_chanctx_switch(sc, ctx, NULL);
928 mod_timer(&sc->offchannel.timer, jiffies + HZ / 10);
929 break;
930 }
931 /* fall through */
932 case ATH_OFFCHANNEL_SUSPEND:
933 if (!sc->offchannel.scan_req)
934 return;
935
936 ath_scan_next_channel(sc);
937 break;
938 case ATH_OFFCHANNEL_ROC_START:
939 case ATH_OFFCHANNEL_ROC_WAIT:
940 ctx = ath_chanctx_get_oper_chan(sc, false);
941 sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE;
942 ath_chanctx_switch(sc, ctx, NULL);
943 break;
944 default:
945 break;
946 }
947}
Sujith Manoharan2471adf2014-08-22 20:39:29 +0530948
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +0530949static bool
950ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
951 bool powersave)
952{
953 struct ieee80211_vif *vif = avp->vif;
954 struct ieee80211_sta *sta = NULL;
955 struct ieee80211_hdr_3addr *nullfunc;
956 struct ath_tx_control txctl;
957 struct sk_buff *skb;
958 int band = sc->cur_chan->chandef.chan->band;
959
960 switch (vif->type) {
961 case NL80211_IFTYPE_STATION:
Sujith Manoharancb355822014-09-17 14:45:56 +0530962 if (!avp->assoc)
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +0530963 return false;
964
965 skb = ieee80211_nullfunc_get(sc->hw, vif);
966 if (!skb)
967 return false;
968
969 nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
970 if (powersave)
971 nullfunc->frame_control |=
972 cpu_to_le16(IEEE80211_FCTL_PM);
973
974 skb_set_queue_mapping(skb, IEEE80211_AC_VO);
975 if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
976 dev_kfree_skb_any(skb);
977 return false;
978 }
979 break;
980 default:
981 return false;
982 }
983
984 memset(&txctl, 0, sizeof(txctl));
985 txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
986 txctl.sta = sta;
987 txctl.force_channel = true;
988 if (ath_tx_start(sc->hw, skb, &txctl)) {
989 ieee80211_free_txskb(sc->hw, skb);
990 return false;
991 }
992
993 return true;
994}
995
996static bool
997ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave)
998{
999 struct ath_vif *avp;
1000 bool sent = false;
1001
1002 rcu_read_lock();
1003 list_for_each_entry(avp, &sc->cur_chan->vifs, list) {
1004 if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave))
1005 sent = true;
1006 }
1007 rcu_read_unlock();
1008
1009 return sent;
1010}
1011
1012static bool ath_chanctx_defer_switch(struct ath_softc *sc)
1013{
Sujith Manoharan878066e2014-08-27 12:07:24 +05301014 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1015
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +05301016 if (sc->cur_chan == &sc->offchannel.chan)
1017 return false;
1018
1019 switch (sc->sched.state) {
1020 case ATH_CHANCTX_STATE_SWITCH:
1021 return false;
1022 case ATH_CHANCTX_STATE_IDLE:
1023 if (!sc->cur_chan->switch_after_beacon)
1024 return false;
1025
Sujith Manoharan878066e2014-08-27 12:07:24 +05301026 ath_dbg(common, CHAN_CTX,
1027 "Defer switch, set chanctx state to WAIT_FOR_BEACON\n");
1028
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +05301029 sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
1030 break;
1031 default:
1032 break;
1033 }
1034
1035 return true;
1036}
1037
Sujith Manoharan55254ee2014-08-23 13:29:11 +05301038static void ath_offchannel_channel_change(struct ath_softc *sc)
1039{
1040 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1041
Sujith Manoharan878066e2014-08-27 12:07:24 +05301042 ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n",
Sujith Manoharan55254ee2014-08-23 13:29:11 +05301043 __func__, offchannel_state_string(sc->offchannel.state));
1044
1045 switch (sc->offchannel.state) {
1046 case ATH_OFFCHANNEL_PROBE_SEND:
1047 if (!sc->offchannel.scan_req)
1048 return;
1049
1050 if (sc->cur_chan->chandef.chan !=
1051 sc->offchannel.chan.chandef.chan)
1052 return;
1053
1054 ath_scan_channel_start(sc);
1055 break;
1056 case ATH_OFFCHANNEL_IDLE:
1057 if (!sc->offchannel.scan_req)
1058 return;
1059
1060 ath_scan_complete(sc, false);
1061 break;
1062 case ATH_OFFCHANNEL_ROC_START:
1063 if (sc->cur_chan != &sc->offchannel.chan)
1064 break;
1065
1066 sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT;
Sujith Manoharanbb628eb2014-09-05 08:03:13 +05301067 mod_timer(&sc->offchannel.timer,
1068 jiffies + sc->offchannel.duration);
Sujith Manoharan55254ee2014-08-23 13:29:11 +05301069 ieee80211_ready_on_channel(sc->hw);
1070 break;
1071 case ATH_OFFCHANNEL_ROC_DONE:
1072 ath_roc_complete(sc, false);
1073 break;
1074 default:
1075 break;
1076 }
1077}
1078
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +05301079void ath_chanctx_set_next(struct ath_softc *sc, bool force)
1080{
Sujith Manoharan878066e2014-08-27 12:07:24 +05301081 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith Manoharane2cba8d2014-10-02 06:33:20 +05301082 struct ath_chanctx *old_ctx;
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +05301083 struct timespec ts;
1084 bool measure_time = false;
1085 bool send_ps = false;
Sujith Manoharane2cba8d2014-10-02 06:33:20 +05301086 bool queues_stopped = false;
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +05301087
1088 spin_lock_bh(&sc->chan_lock);
1089 if (!sc->next_chan) {
1090 spin_unlock_bh(&sc->chan_lock);
1091 return;
1092 }
1093
1094 if (!force && ath_chanctx_defer_switch(sc)) {
1095 spin_unlock_bh(&sc->chan_lock);
1096 return;
1097 }
1098
Sujith Manoharan878066e2014-08-27 12:07:24 +05301099 ath_dbg(common, CHAN_CTX,
1100 "%s: current: %d MHz, next: %d MHz\n",
1101 __func__,
1102 sc->cur_chan->chandef.center_freq1,
1103 sc->next_chan->chandef.center_freq1);
1104
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +05301105 if (sc->cur_chan != sc->next_chan) {
Sujith Manoharan878066e2014-08-27 12:07:24 +05301106 ath_dbg(common, CHAN_CTX,
1107 "Stopping current chanctx: %d\n",
1108 sc->cur_chan->chandef.center_freq1);
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +05301109 sc->cur_chan->stopped = true;
1110 spin_unlock_bh(&sc->chan_lock);
1111
1112 if (sc->next_chan == &sc->offchannel.chan) {
1113 getrawmonotonic(&ts);
1114 measure_time = true;
1115 }
Sujith Manoharane2cba8d2014-10-02 06:33:20 +05301116
1117 ath9k_chanctx_stop_queues(sc, sc->cur_chan);
1118 queues_stopped = true;
1119
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +05301120 __ath9k_flush(sc->hw, ~0, true);
1121
1122 if (ath_chanctx_send_ps_frame(sc, true))
1123 __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
1124
1125 send_ps = true;
1126 spin_lock_bh(&sc->chan_lock);
1127
1128 if (sc->cur_chan != &sc->offchannel.chan) {
1129 getrawmonotonic(&sc->cur_chan->tsf_ts);
1130 sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah);
1131 }
1132 }
Sujith Manoharane2cba8d2014-10-02 06:33:20 +05301133 old_ctx = sc->cur_chan;
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +05301134 sc->cur_chan = sc->next_chan;
1135 sc->cur_chan->stopped = false;
1136 sc->next_chan = NULL;
Sujith Manoharan124130d2014-09-10 19:15:58 +05301137
1138 if (!sc->sched.offchannel_pending)
1139 sc->sched.offchannel_duration = 0;
1140
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +05301141 if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE)
1142 sc->sched.state = ATH_CHANCTX_STATE_IDLE;
1143
1144 spin_unlock_bh(&sc->chan_lock);
1145
1146 if (sc->sc_ah->chip_fullsleep ||
1147 memcmp(&sc->cur_chandef, &sc->cur_chan->chandef,
1148 sizeof(sc->cur_chandef))) {
Sujith Manoharan878066e2014-08-27 12:07:24 +05301149 ath_dbg(common, CHAN_CTX,
1150 "%s: Set channel %d MHz\n",
1151 __func__, sc->cur_chan->chandef.center_freq1);
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +05301152 ath_set_channel(sc);
1153 if (measure_time)
1154 sc->sched.channel_switch_time =
1155 ath9k_hw_get_tsf_offset(&ts, NULL);
Sujith Manoharane2cba8d2014-10-02 06:33:20 +05301156 /*
1157 * A reset will ensure that all queues are woken up,
1158 * so there is no need to awaken them again.
1159 */
1160 goto out;
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +05301161 }
Sujith Manoharane2cba8d2014-10-02 06:33:20 +05301162
1163 if (queues_stopped)
1164 ath9k_chanctx_wake_queues(sc, old_ctx);
1165out:
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +05301166 if (send_ps)
1167 ath_chanctx_send_ps_frame(sc, false);
1168
1169 ath_offchannel_channel_change(sc);
1170 ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH);
1171}
1172
Sujith Manoharan0e62f8b2014-08-23 13:29:08 +05301173static void ath_chanctx_work(struct work_struct *work)
1174{
1175 struct ath_softc *sc = container_of(work, struct ath_softc,
1176 chanctx_work);
1177 mutex_lock(&sc->mutex);
1178 ath_chanctx_set_next(sc, false);
1179 mutex_unlock(&sc->mutex);
1180}
1181
Sujith Manoharane90e3022014-08-23 13:29:20 +05301182void ath9k_offchannel_init(struct ath_softc *sc)
1183{
1184 struct ath_chanctx *ctx;
1185 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1186 struct ieee80211_supported_band *sband;
1187 struct ieee80211_channel *chan;
1188 int i;
1189
1190 sband = &common->sbands[IEEE80211_BAND_2GHZ];
1191 if (!sband->n_channels)
1192 sband = &common->sbands[IEEE80211_BAND_5GHZ];
1193
1194 chan = &sband->channels[0];
1195
1196 ctx = &sc->offchannel.chan;
1197 INIT_LIST_HEAD(&ctx->vifs);
1198 ctx->txpower = ATH_TXPOWER_MAX;
1199 cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
1200
1201 for (i = 0; i < ARRAY_SIZE(ctx->acq); i++)
1202 INIT_LIST_HEAD(&ctx->acq[i]);
1203
1204 sc->offchannel.chan.offchannel = true;
1205}
1206
Sujith Manoharan705d0bf2014-08-23 13:29:06 +05301207void ath9k_init_channel_context(struct ath_softc *sc)
1208{
1209 INIT_WORK(&sc->chanctx_work, ath_chanctx_work);
1210
1211 setup_timer(&sc->offchannel.timer, ath_offchannel_timer,
1212 (unsigned long)sc);
1213 setup_timer(&sc->sched.timer, ath_chanctx_timer,
1214 (unsigned long)sc);
1215}
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +05301216
Sujith Manoharanea22df22014-08-23 13:29:07 +05301217void ath9k_deinit_channel_context(struct ath_softc *sc)
1218{
1219 cancel_work_sync(&sc->chanctx_work);
1220}
1221
Sujith Manoharan499afac2014-08-22 20:39:31 +05301222bool ath9k_is_chanctx_enabled(void)
1223{
1224 return (ath9k_use_chanctx == 1);
1225}
1226
Sujith Manoharan0e08b5f2014-08-23 13:29:19 +05301227/********************/
1228/* Queue management */
1229/********************/
1230
Sujith Manoharana064eaa2014-10-02 06:33:18 +05301231void ath9k_chanctx_stop_queues(struct ath_softc *sc, struct ath_chanctx *ctx)
1232{
1233 struct ath_hw *ah = sc->sc_ah;
1234 int i;
1235
1236 if (ctx == &sc->offchannel.chan) {
1237 ieee80211_stop_queue(sc->hw,
1238 sc->hw->offchannel_tx_hw_queue);
1239 } else {
1240 for (i = 0; i < IEEE80211_NUM_ACS; i++)
1241 ieee80211_stop_queue(sc->hw,
1242 ctx->hw_queue_base + i);
1243 }
1244
1245 if (ah->opmode == NL80211_IFTYPE_AP)
1246 ieee80211_stop_queue(sc->hw, sc->hw->queues - 2);
1247}
1248
1249
Sujith Manoharanb3903152014-10-02 06:33:17 +05301250void ath9k_chanctx_wake_queues(struct ath_softc *sc, struct ath_chanctx *ctx)
Sujith Manoharan0e08b5f2014-08-23 13:29:19 +05301251{
1252 struct ath_hw *ah = sc->sc_ah;
1253 int i;
1254
Sujith Manoharanb3903152014-10-02 06:33:17 +05301255 if (ctx == &sc->offchannel.chan) {
Sujith Manoharan0e08b5f2014-08-23 13:29:19 +05301256 ieee80211_wake_queue(sc->hw,
1257 sc->hw->offchannel_tx_hw_queue);
1258 } else {
1259 for (i = 0; i < IEEE80211_NUM_ACS; i++)
1260 ieee80211_wake_queue(sc->hw,
Sujith Manoharanb3903152014-10-02 06:33:17 +05301261 ctx->hw_queue_base + i);
Sujith Manoharan0e08b5f2014-08-23 13:29:19 +05301262 }
1263
1264 if (ah->opmode == NL80211_IFTYPE_AP)
1265 ieee80211_wake_queue(sc->hw, sc->hw->queues - 2);
1266}
1267
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +05301268/*****************/
1269/* P2P Powersave */
1270/*****************/
1271
1272static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
Sujith Manoharan2471adf2014-08-22 20:39:29 +05301273{
1274 struct ath_hw *ah = sc->sc_ah;
1275 s32 tsf, target_tsf;
1276
1277 if (!avp || !avp->noa.has_next_tsf)
1278 return;
1279
1280 ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer);
1281
1282 tsf = ath9k_hw_gettsf32(sc->sc_ah);
1283
1284 target_tsf = avp->noa.next_tsf;
1285 if (!avp->noa.absent)
1286 target_tsf -= ATH_P2P_PS_STOP_TIME;
1287
1288 if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
1289 target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
1290
1291 ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
1292}
1293
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +05301294static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
1295{
1296 struct ath_vif *avp = (void *)vif->drv_priv;
1297 u32 tsf;
1298
1299 if (!sc->p2p_ps_timer)
1300 return;
1301
1302 if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
1303 return;
1304
1305 sc->p2p_ps_vif = avp;
1306 tsf = ath9k_hw_gettsf32(sc->sc_ah);
1307 ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
1308 ath9k_update_p2p_ps_timer(sc, avp);
1309}
1310
Sujith Manoharanfdcf1bd2014-09-05 08:03:14 +05301311static u8 ath9k_get_ctwin(struct ath_softc *sc, struct ath_vif *avp)
1312{
1313 struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
1314 u8 switch_time, ctwin;
1315
1316 /*
1317 * Channel switch in multi-channel mode is deferred
1318 * by a quarter beacon interval when handling
1319 * ATH_CHANCTX_EVENT_BEACON_PREPARE, so the P2P-GO
1320 * interface is guaranteed to be discoverable
1321 * for that duration after a TBTT.
1322 */
1323 switch_time = cur_conf->beacon_interval / 4;
1324
1325 ctwin = avp->vif->bss_conf.p2p_noa_attr.oppps_ctwindow;
1326 if (ctwin && (ctwin < switch_time))
1327 return ctwin;
1328
1329 if (switch_time < P2P_DEFAULT_CTWIN)
1330 return 0;
1331
1332 return P2P_DEFAULT_CTWIN;
1333}
1334
Sujith Manoharan11e39a42014-08-23 19:12:15 +05301335void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
1336 struct sk_buff *skb)
1337{
1338 static const u8 noa_ie_hdr[] = {
1339 WLAN_EID_VENDOR_SPECIFIC, /* type */
1340 0, /* length */
1341 0x50, 0x6f, 0x9a, /* WFA OUI */
1342 0x09, /* P2P subtype */
1343 0x0c, /* Notice of Absence */
1344 0x00, /* LSB of little-endian len */
1345 0x00, /* MSB of little-endian len */
1346 };
1347
1348 struct ieee80211_p2p_noa_attr *noa;
1349 int noa_len, noa_desc, i = 0;
1350 u8 *hdr;
1351
Sujith Manoharand0975ed2014-09-10 19:15:57 +05301352 if (!avp->offchannel_duration && !avp->noa_duration)
Sujith Manoharan11e39a42014-08-23 19:12:15 +05301353 return;
1354
Sujith Manoharand0975ed2014-09-10 19:15:57 +05301355 noa_desc = !!avp->offchannel_duration + !!avp->noa_duration;
Sujith Manoharan11e39a42014-08-23 19:12:15 +05301356 noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc;
1357
1358 hdr = skb_put(skb, sizeof(noa_ie_hdr));
1359 memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr));
1360 hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2;
1361 hdr[7] = noa_len;
1362
1363 noa = (void *) skb_put(skb, noa_len);
1364 memset(noa, 0, noa_len);
1365
1366 noa->index = avp->noa_index;
Sujith Manoharanfdcf1bd2014-09-05 08:03:14 +05301367 noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp);
1368
Sujith Manoharand0975ed2014-09-10 19:15:57 +05301369 if (avp->noa_duration) {
1370 if (avp->periodic_noa) {
1371 u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
1372 noa->desc[i].count = 255;
1373 noa->desc[i].interval = cpu_to_le32(interval);
1374 } else {
1375 noa->desc[i].count = 1;
1376 }
Sujith Manoharan11e39a42014-08-23 19:12:15 +05301377
Sujith Manoharand0975ed2014-09-10 19:15:57 +05301378 noa->desc[i].start_time = cpu_to_le32(avp->noa_start);
1379 noa->desc[i].duration = cpu_to_le32(avp->noa_duration);
Sujith Manoharan11e39a42014-08-23 19:12:15 +05301380 i++;
1381 }
1382
1383 if (avp->offchannel_duration) {
1384 noa->desc[i].count = 1;
1385 noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start);
1386 noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration);
1387 }
1388}
1389
Sujith Manoharan2471adf2014-08-22 20:39:29 +05301390void ath9k_p2p_ps_timer(void *priv)
1391{
1392 struct ath_softc *sc = priv;
1393 struct ath_vif *avp = sc->p2p_ps_vif;
1394 struct ieee80211_vif *vif;
1395 struct ieee80211_sta *sta;
1396 struct ath_node *an;
1397 u32 tsf;
1398
1399 del_timer_sync(&sc->sched.timer);
1400 ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer);
1401 ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
1402
1403 if (!avp || avp->chanctx != sc->cur_chan)
1404 return;
1405
1406 tsf = ath9k_hw_gettsf32(sc->sc_ah);
1407 if (!avp->noa.absent)
1408 tsf += ATH_P2P_PS_STOP_TIME;
1409
1410 if (!avp->noa.has_next_tsf ||
1411 avp->noa.next_tsf - tsf > BIT(31))
1412 ieee80211_update_p2p_noa(&avp->noa, tsf);
1413
1414 ath9k_update_p2p_ps_timer(sc, avp);
1415
1416 rcu_read_lock();
1417
1418 vif = avp->vif;
Sujith Manoharancb355822014-09-17 14:45:56 +05301419 sta = ieee80211_find_sta(vif, avp->bssid);
Sujith Manoharan2471adf2014-08-22 20:39:29 +05301420 if (!sta)
1421 goto out;
1422
1423 an = (void *) sta->drv_priv;
1424 if (an->sleeping == !!avp->noa.absent)
1425 goto out;
1426
1427 an->sleeping = avp->noa.absent;
1428 if (an->sleeping)
1429 ath_tx_aggr_sleep(sta, sc, an);
1430 else
1431 ath_tx_aggr_wakeup(sc, an);
1432
1433out:
1434 rcu_read_unlock();
1435}
1436
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +05301437void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
1438 struct ieee80211_vif *vif)
1439{
1440 unsigned long flags;
1441
1442 spin_lock_bh(&sc->sc_pcu_lock);
1443 spin_lock_irqsave(&sc->sc_pm_lock, flags);
1444 if (!(sc->ps_flags & PS_BEACON_SYNC))
1445 ath9k_update_p2p_ps(sc, vif);
1446 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
1447 spin_unlock_bh(&sc->sc_pcu_lock);
1448}
1449
1450void ath9k_p2p_beacon_sync(struct ath_softc *sc)
1451{
1452 if (sc->p2p_ps_vif)
1453 ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
1454}
1455
1456void ath9k_p2p_remove_vif(struct ath_softc *sc,
1457 struct ieee80211_vif *vif)
Sujith Manoharan2471adf2014-08-22 20:39:29 +05301458{
1459 struct ath_vif *avp = (void *)vif->drv_priv;
Sujith Manoharan2471adf2014-08-22 20:39:29 +05301460
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +05301461 spin_lock_bh(&sc->sc_pcu_lock);
1462 if (avp == sc->p2p_ps_vif) {
1463 sc->p2p_ps_vif = NULL;
1464 ath9k_update_p2p_ps_timer(sc, NULL);
1465 }
1466 spin_unlock_bh(&sc->sc_pcu_lock);
Sujith Manoharan2471adf2014-08-22 20:39:29 +05301467}
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +05301468
1469int ath9k_init_p2p(struct ath_softc *sc)
1470{
1471 sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer,
1472 NULL, sc, AR_FIRST_NDP_TIMER);
1473 if (!sc->p2p_ps_timer)
1474 return -ENOMEM;
1475
1476 return 0;
1477}
1478
1479void ath9k_deinit_p2p(struct ath_softc *sc)
1480{
1481 if (sc->p2p_ps_timer)
1482 ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
1483}
1484
1485#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */