blob: 0e64b736160eb9e55a500682f1d7e71a33f9162c [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];
69 r = ath_reset_internal(sc, hchan);
70 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
86 /* set HW specific DFS configuration */
87 ath9k_hw_set_radar_params(ah);
88 rxfilter = ath9k_hw_getrxfilter(ah);
89 rxfilter |= ATH9K_RX_FILTER_PHYRADAR |
90 ATH9K_RX_FILTER_PHYERR;
91 ath9k_hw_setrxfilter(ah, rxfilter);
92 ath_dbg(common, DFS, "DFS enabled at freq %d\n",
93 chan->center_freq);
94 } else {
95 /* perform spectral scan if requested. */
96 if (test_bit(ATH_OP_SCANNING, &common->op_flags) &&
97 sc->spectral_mode == SPECTRAL_CHANSCAN)
98 ath9k_spectral_scan_trigger(hw);
99 }
100
101 return 0;
102}
103
104void ath_chanctx_init(struct ath_softc *sc)
105{
106 struct ath_chanctx *ctx;
107 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
108 struct ieee80211_supported_band *sband;
109 struct ieee80211_channel *chan;
Felix Fietkau04535312014-06-11 16:17:51 +0530110 int i, j;
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530111
112 sband = &common->sbands[IEEE80211_BAND_2GHZ];
113 if (!sband->n_channels)
114 sband = &common->sbands[IEEE80211_BAND_5GHZ];
115
116 chan = &sband->channels[0];
117 for (i = 0; i < ATH9K_NUM_CHANCTX; i++) {
118 ctx = &sc->chanctx[i];
119 cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
120 INIT_LIST_HEAD(&ctx->vifs);
Felix Fietkaubc7e1be2014-06-11 16:17:50 +0530121 ctx->txpower = ATH_TXPOWER_MAX;
Felix Fietkau04535312014-06-11 16:17:51 +0530122 for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
123 INIT_LIST_HEAD(&ctx->acq[j]);
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530124 }
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530125}
126
Felix Fietkaubff11762014-06-11 16:17:52 +0530127void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
128 struct cfg80211_chan_def *chandef)
129{
130 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
138 if (!cur_chan)
139 return;
140
141 ath_set_channel(sc);
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530142}
Felix Fietkau78b21942014-06-11 16:17:55 +0530143
Sujith Manoharan27babf92014-08-23 13:29:16 +0530144#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
145
Sujith Manoharan0e08b5f2014-08-23 13:29:19 +0530146/**********************************************************/
147/* Functions to handle the channel context state machine. */
148/**********************************************************/
149
Sujith Manoharan27babf92014-08-23 13:29:16 +0530150static const char *offchannel_state_string(enum ath_offchannel_state state)
151{
152#define case_rtn_string(val) case val: return #val
153
154 switch (state) {
155 case_rtn_string(ATH_OFFCHANNEL_IDLE);
156 case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND);
157 case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT);
158 case_rtn_string(ATH_OFFCHANNEL_SUSPEND);
159 case_rtn_string(ATH_OFFCHANNEL_ROC_START);
160 case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT);
161 case_rtn_string(ATH_OFFCHANNEL_ROC_DONE);
162 default:
163 return "unknown";
164 }
165}
166
Sujith Manoharana09798f2014-08-23 13:29:21 +0530167void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
168{
169 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
170 struct ath_vif *avp;
171 bool active = false;
172 u8 n_active = 0;
173
174 if (!ctx)
175 return;
176
177 list_for_each_entry(avp, &ctx->vifs, list) {
178 struct ieee80211_vif *vif = avp->vif;
179
180 switch (vif->type) {
181 case NL80211_IFTYPE_P2P_CLIENT:
182 case NL80211_IFTYPE_STATION:
183 if (vif->bss_conf.assoc)
184 active = true;
185 break;
186 default:
187 active = true;
188 break;
189 }
190 }
191 ctx->active = active;
192
193 ath_for_each_chanctx(sc, ctx) {
194 if (!ctx->assigned || list_empty(&ctx->vifs))
195 continue;
196 n_active++;
197 }
198
199 if (n_active <= 1) {
200 clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags);
201 return;
202 }
203 if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
204 return;
205
206 if (ath9k_is_chanctx_enabled()) {
207 ath_chanctx_event(sc, NULL,
208 ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
209 }
210}
211
Felix Fietkau58b57372014-06-11 16:18:08 +0530212static struct ath_chanctx *
213ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx)
214{
215 int idx = ctx - &sc->chanctx[0];
216
217 return &sc->chanctx[!idx];
218}
219
220static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc)
221{
222 struct ath_chanctx *prev, *cur;
223 struct timespec ts;
224 u32 cur_tsf, prev_tsf, beacon_int;
225 s32 offset;
226
227 beacon_int = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
228
229 cur = sc->cur_chan;
230 prev = ath_chanctx_get_next(sc, cur);
231
232 getrawmonotonic(&ts);
233 cur_tsf = (u32) cur->tsf_val +
234 ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts);
235
236 prev_tsf = prev->last_beacon - (u32) prev->tsf_val + cur_tsf;
237 prev_tsf -= ath9k_hw_get_tsf_offset(&prev->tsf_ts, &ts);
238
239 /* Adjust the TSF time of the AP chanctx to keep its beacons
240 * at half beacon interval offset relative to the STA chanctx.
241 */
242 offset = cur_tsf - prev_tsf;
243
244 /* Ignore stale data or spurious timestamps */
245 if (offset < 0 || offset > 3 * beacon_int)
246 return;
247
248 offset = beacon_int / 2 - (offset % beacon_int);
249 prev->tsf_val += offset;
250}
251
Felix Fietkau42eda112014-06-11 16:18:14 +0530252/* Configure the TSF based hardware timer for a channel switch.
253 * Also set up backup software timer, in case the gen timer fails.
254 * This could be caused by a hardware reset.
255 */
256static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
257{
258 struct ath_hw *ah = sc->sc_ah;
259
260 ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000);
261 tsf_time -= ath9k_hw_gettsf32(ah);
262 tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1;
263 mod_timer(&sc->sched.timer, tsf_time);
264}
265
Felix Fietkau748299f2014-06-11 16:18:04 +0530266void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
267 enum ath_chanctx_event ev)
268{
269 struct ath_hw *ah = sc->sc_ah;
Felix Fietkau58b57372014-06-11 16:18:08 +0530270 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkau74148632014-06-11 16:18:11 +0530271 struct ath_beacon_config *cur_conf;
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530272 struct ath_vif *avp = NULL;
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530273 struct ath_chanctx *ctx;
Felix Fietkau748299f2014-06-11 16:18:04 +0530274 u32 tsf_time;
Felix Fietkauec70abe2014-06-11 16:18:12 +0530275 u32 beacon_int;
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530276 bool noa_changed = false;
277
278 if (vif)
279 avp = (struct ath_vif *) vif->drv_priv;
Felix Fietkau748299f2014-06-11 16:18:04 +0530280
281 spin_lock_bh(&sc->chan_lock);
282
283 switch (ev) {
284 case ATH_CHANCTX_EVENT_BEACON_PREPARE:
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530285 if (avp->offchannel_duration)
286 avp->offchannel_duration = 0;
287
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530288 if (avp->chanctx != sc->cur_chan)
289 break;
290
291 if (sc->sched.offchannel_pending) {
292 sc->sched.offchannel_pending = false;
293 sc->next_chan = &sc->offchannel.chan;
294 sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
295 }
296
297 ctx = ath_chanctx_get_next(sc, sc->cur_chan);
298 if (ctx->active && sc->sched.state == ATH_CHANCTX_STATE_IDLE) {
299 sc->next_chan = ctx;
300 sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
301 }
302
303 /* if the timer missed its window, use the next interval */
304 if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER)
305 sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
306
Felix Fietkau748299f2014-06-11 16:18:04 +0530307 if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
308 break;
309
310 sc->sched.beacon_pending = true;
311 sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER);
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530312
Felix Fietkau74148632014-06-11 16:18:11 +0530313 cur_conf = &sc->cur_chan->beacon;
Felix Fietkauec70abe2014-06-11 16:18:12 +0530314 beacon_int = TU_TO_USEC(cur_conf->beacon_interval);
315
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530316 /* defer channel switch by a quarter beacon interval */
Felix Fietkauec70abe2014-06-11 16:18:12 +0530317 tsf_time = sc->sched.next_tbtt + beacon_int / 4;
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530318 sc->sched.switch_start_time = tsf_time;
Felix Fietkau58b57372014-06-11 16:18:08 +0530319 sc->cur_chan->last_beacon = sc->sched.next_tbtt;
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530320
Felix Fietkau74148632014-06-11 16:18:11 +0530321 /* Prevent wrap-around issues */
322 if (avp->periodic_noa_duration &&
323 tsf_time - avp->periodic_noa_start > BIT(30))
324 avp->periodic_noa_duration = 0;
325
326 if (ctx->active && !avp->periodic_noa_duration) {
327 avp->periodic_noa_start = tsf_time;
328 avp->periodic_noa_duration =
329 TU_TO_USEC(cur_conf->beacon_interval) / 2 -
330 sc->sched.channel_switch_time;
331 noa_changed = true;
332 } else if (!ctx->active && avp->periodic_noa_duration) {
333 avp->periodic_noa_duration = 0;
334 noa_changed = true;
335 }
336
Felix Fietkauec70abe2014-06-11 16:18:12 +0530337 /* If at least two consecutive beacons were missed on the STA
338 * chanctx, stay on the STA channel for one extra beacon period,
339 * to resync the timer properly.
340 */
341 if (ctx->active && sc->sched.beacon_miss >= 2)
342 sc->sched.offchannel_duration = 3 * beacon_int / 2;
343
Felix Fietkau3ae07d32014-06-11 16:18:06 +0530344 if (sc->sched.offchannel_duration) {
345 noa_changed = true;
346 avp->offchannel_start = tsf_time;
347 avp->offchannel_duration =
348 sc->sched.offchannel_duration;
349 }
350
351 if (noa_changed)
352 avp->noa_index++;
Felix Fietkau748299f2014-06-11 16:18:04 +0530353 break;
354 case ATH_CHANCTX_EVENT_BEACON_SENT:
355 if (!sc->sched.beacon_pending)
356 break;
357
358 sc->sched.beacon_pending = false;
359 if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
360 break;
361
Felix Fietkau748299f2014-06-11 16:18:04 +0530362 sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
Felix Fietkau42eda112014-06-11 16:18:14 +0530363 ath_chanctx_setup_timer(sc, sc->sched.switch_start_time);
Felix Fietkau748299f2014-06-11 16:18:04 +0530364 break;
365 case ATH_CHANCTX_EVENT_TSF_TIMER:
366 if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_TIMER)
367 break;
368
Felix Fietkauec70abe2014-06-11 16:18:12 +0530369 if (!sc->cur_chan->switch_after_beacon &&
370 sc->sched.beacon_pending)
371 sc->sched.beacon_miss++;
372
Felix Fietkau748299f2014-06-11 16:18:04 +0530373 sc->sched.state = ATH_CHANCTX_STATE_SWITCH;
374 ieee80211_queue_work(sc->hw, &sc->chanctx_work);
375 break;
Felix Fietkau58b57372014-06-11 16:18:08 +0530376 case ATH_CHANCTX_EVENT_BEACON_RECEIVED:
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530377 if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) ||
378 sc->cur_chan == &sc->offchannel.chan)
Felix Fietkau58b57372014-06-11 16:18:08 +0530379 break;
380
381 ath_chanctx_adjust_tbtt_delta(sc);
Felix Fietkauec70abe2014-06-11 16:18:12 +0530382 sc->sched.beacon_pending = false;
383 sc->sched.beacon_miss = 0;
Felix Fietkaua899b672014-06-11 16:18:13 +0530384
385 /* TSF time might have been updated by the incoming beacon,
386 * need update the channel switch timer to reflect the change.
387 */
388 tsf_time = sc->sched.switch_start_time;
389 tsf_time -= (u32) sc->cur_chan->tsf_val +
390 ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL);
391 tsf_time += ath9k_hw_gettsf32(ah);
392
Felix Fietkau42eda112014-06-11 16:18:14 +0530393
394 ath_chanctx_setup_timer(sc, tsf_time);
Felix Fietkau58b57372014-06-11 16:18:08 +0530395 break;
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530396 case ATH_CHANCTX_EVENT_ASSOC:
397 if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE ||
398 avp->chanctx != sc->cur_chan)
399 break;
400
401 sc->sched.state = ATH_CHANCTX_STATE_IDLE;
402 /* fall through */
403 case ATH_CHANCTX_EVENT_SWITCH:
404 if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) ||
405 sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE ||
406 sc->cur_chan->switch_after_beacon ||
407 sc->cur_chan == &sc->offchannel.chan)
408 break;
409
410 /* If this is a station chanctx, stay active for a half
411 * beacon period (minus channel switch time)
412 */
413 sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan);
Felix Fietkau74148632014-06-11 16:18:11 +0530414 cur_conf = &sc->cur_chan->beacon;
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530415
416 sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
Felix Fietkauec70abe2014-06-11 16:18:12 +0530417
418 tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2;
419 if (sc->sched.beacon_miss >= 2) {
420 sc->sched.beacon_miss = 0;
421 tsf_time *= 3;
422 }
423
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530424 tsf_time -= sc->sched.channel_switch_time;
Felix Fietkauec70abe2014-06-11 16:18:12 +0530425 tsf_time += ath9k_hw_gettsf32(sc->sc_ah);
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530426 sc->sched.switch_start_time = tsf_time;
427
Felix Fietkau42eda112014-06-11 16:18:14 +0530428 ath_chanctx_setup_timer(sc, tsf_time);
Felix Fietkauec70abe2014-06-11 16:18:12 +0530429 sc->sched.beacon_pending = true;
Felix Fietkau73fa2f22014-06-11 16:18:10 +0530430 break;
431 case ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL:
432 if (sc->cur_chan == &sc->offchannel.chan ||
433 sc->cur_chan->switch_after_beacon)
434 break;
435
436 sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan);
437 ieee80211_queue_work(sc->hw, &sc->chanctx_work);
438 break;
439 case ATH_CHANCTX_EVENT_UNASSIGN:
440 if (sc->cur_chan->assigned) {
441 if (sc->next_chan && !sc->next_chan->assigned &&
442 sc->next_chan != &sc->offchannel.chan)
443 sc->sched.state = ATH_CHANCTX_STATE_IDLE;
444 break;
445 }
446
447 ctx = ath_chanctx_get_next(sc, sc->cur_chan);
448 sc->sched.state = ATH_CHANCTX_STATE_IDLE;
449 if (!ctx->assigned)
450 break;
451
452 sc->next_chan = ctx;
453 ieee80211_queue_work(sc->hw, &sc->chanctx_work);
454 break;
Felix Fietkau748299f2014-06-11 16:18:04 +0530455 }
456
457 spin_unlock_bh(&sc->chan_lock);
458}
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530459
Sujith Manoharan70b06da2014-08-23 13:29:18 +0530460void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
461 enum ath_chanctx_event ev)
462{
463 if (sc->sched.beacon_pending)
464 ath_chanctx_event(sc, NULL, ev);
465}
466
467void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts,
468 enum ath_chanctx_event ev)
469{
470 sc->sched.next_tbtt = ts;
471 ath_chanctx_event(sc, NULL, ev);
472}
473
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530474static int ath_scan_channel_duration(struct ath_softc *sc,
475 struct ieee80211_channel *chan)
476{
477 struct cfg80211_scan_request *req = sc->offchannel.scan_req;
478
479 if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR))
480 return (HZ / 9); /* ~110 ms */
481
482 return (HZ / 16); /* ~60 ms */
483}
484
Sujith Manoharan922c9432014-08-23 13:29:15 +0530485static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
486 struct cfg80211_chan_def *chandef)
487{
488 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
489
490 spin_lock_bh(&sc->chan_lock);
491
492 if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) &&
493 (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) {
494 sc->sched.offchannel_pending = true;
495 spin_unlock_bh(&sc->chan_lock);
496 return;
497 }
498
499 sc->next_chan = ctx;
500 if (chandef) {
501 ctx->chandef = *chandef;
502 ath_dbg(common, CHAN_CTX,
503 "Assigned next_chan to %d MHz\n", chandef->center_freq1);
504 }
505
506 if (sc->next_chan == &sc->offchannel.chan) {
507 sc->sched.offchannel_duration =
508 TU_TO_USEC(sc->offchannel.duration) +
509 sc->sched.channel_switch_time;
510
511 if (chandef) {
512 ath_dbg(common, CHAN_CTX,
513 "Offchannel duration for chan %d MHz : %u\n",
514 chandef->center_freq1,
515 sc->sched.offchannel_duration);
516 }
517 }
518 spin_unlock_bh(&sc->chan_lock);
519 ieee80211_queue_work(sc->hw, &sc->chanctx_work);
520}
521
Sujith Manoharan344ae6a2014-08-23 13:29:13 +0530522static void ath_chanctx_offchan_switch(struct ath_softc *sc,
523 struct ieee80211_channel *chan)
524{
525 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
526 struct cfg80211_chan_def chandef;
527
528 cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
529 ath_dbg(common, CHAN_CTX,
530 "Channel definition created: %d MHz\n", chandef.center_freq1);
531
532 ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef);
533}
534
Sujith Manoharan98f411b2014-08-23 13:29:14 +0530535static struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc,
536 bool active)
537{
538 struct ath_chanctx *ctx;
539
540 ath_for_each_chanctx(sc, ctx) {
541 if (!ctx->assigned || list_empty(&ctx->vifs))
542 continue;
543 if (active && !ctx->active)
544 continue;
545
546 if (ctx->switch_after_beacon)
547 return ctx;
548 }
549
550 return &sc->chanctx[0];
551}
552
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530553static void
554ath_scan_next_channel(struct ath_softc *sc)
555{
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530556 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530557 struct cfg80211_scan_request *req = sc->offchannel.scan_req;
558 struct ieee80211_channel *chan;
559
560 if (sc->offchannel.scan_idx >= req->n_channels) {
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530561 ath_dbg(common, CHAN_CTX,
562 "Moving to ATH_OFFCHANNEL_IDLE state, scan_idx: %d, n_channels: %d\n",
563 sc->offchannel.scan_idx,
564 req->n_channels);
565
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530566 sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
567 ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
568 NULL);
569 return;
570 }
571
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530572 ath_dbg(common, CHAN_CTX,
573 "Moving to ATH_OFFCHANNEL_PROBE_SEND state, scan_idx: %d\n",
574 sc->offchannel.scan_idx);
575
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530576 chan = req->channels[sc->offchannel.scan_idx++];
577 sc->offchannel.duration = ath_scan_channel_duration(sc, chan);
578 sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND;
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530579
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530580 ath_chanctx_offchan_switch(sc, chan);
581}
582
583void ath_offchannel_next(struct ath_softc *sc)
584{
585 struct ieee80211_vif *vif;
586
587 if (sc->offchannel.scan_req) {
588 vif = sc->offchannel.scan_vif;
589 sc->offchannel.chan.txpower = vif->bss_conf.txpower;
590 ath_scan_next_channel(sc);
591 } else if (sc->offchannel.roc_vif) {
592 vif = sc->offchannel.roc_vif;
593 sc->offchannel.chan.txpower = vif->bss_conf.txpower;
594 sc->offchannel.duration = sc->offchannel.roc_duration;
595 sc->offchannel.state = ATH_OFFCHANNEL_ROC_START;
596 ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan);
597 } else {
598 ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
599 NULL);
600 sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
601 if (sc->ps_idle)
602 ath_cancel_work(sc);
603 }
604}
605
606void ath_roc_complete(struct ath_softc *sc, bool abort)
607{
608 sc->offchannel.roc_vif = NULL;
609 sc->offchannel.roc_chan = NULL;
610 if (!abort)
611 ieee80211_remain_on_channel_expired(sc->hw);
612 ath_offchannel_next(sc);
613 ath9k_ps_restore(sc);
614}
615
616void ath_scan_complete(struct ath_softc *sc, bool abort)
617{
618 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
619
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530620 if (abort)
621 ath_dbg(common, CHAN_CTX, "HW scan aborted\n");
622 else
623 ath_dbg(common, CHAN_CTX, "HW scan complete\n");
624
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530625 sc->offchannel.scan_req = NULL;
626 sc->offchannel.scan_vif = NULL;
627 sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
628 ieee80211_scan_completed(sc->hw, abort);
629 clear_bit(ATH_OP_SCANNING, &common->op_flags);
630 ath_offchannel_next(sc);
631 ath9k_ps_restore(sc);
632}
633
634static void ath_scan_send_probe(struct ath_softc *sc,
635 struct cfg80211_ssid *ssid)
636{
637 struct cfg80211_scan_request *req = sc->offchannel.scan_req;
638 struct ieee80211_vif *vif = sc->offchannel.scan_vif;
639 struct ath_tx_control txctl = {};
640 struct sk_buff *skb;
641 struct ieee80211_tx_info *info;
642 int band = sc->offchannel.chan.chandef.chan->band;
643
644 skb = ieee80211_probereq_get(sc->hw, vif,
645 ssid->ssid, ssid->ssid_len, req->ie_len);
646 if (!skb)
647 return;
648
649 info = IEEE80211_SKB_CB(skb);
650 if (req->no_cck)
651 info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
652
653 if (req->ie_len)
654 memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len);
655
656 skb_set_queue_mapping(skb, IEEE80211_AC_VO);
657
658 if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
659 goto error;
660
661 txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
662 txctl.force_channel = true;
663 if (ath_tx_start(sc->hw, skb, &txctl))
664 goto error;
665
666 return;
667
668error:
669 ieee80211_free_txskb(sc->hw, skb);
670}
671
672static void ath_scan_channel_start(struct ath_softc *sc)
673{
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530674 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530675 struct cfg80211_scan_request *req = sc->offchannel.scan_req;
676 int i;
677
678 if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) &&
679 req->n_ssids) {
680 for (i = 0; i < req->n_ssids; i++)
681 ath_scan_send_probe(sc, &req->ssids[i]);
682
683 }
684
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530685 ath_dbg(common, CHAN_CTX,
686 "Moving to ATH_OFFCHANNEL_PROBE_WAIT state\n");
687
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530688 sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT;
689 mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration);
690}
691
Sujith Manoharan705d0bf2014-08-23 13:29:06 +0530692static void ath_chanctx_timer(unsigned long data)
693{
694 struct ath_softc *sc = (struct ath_softc *) data;
695
696 ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
697}
698
699static void ath_offchannel_timer(unsigned long data)
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530700{
701 struct ath_softc *sc = (struct ath_softc *)data;
702 struct ath_chanctx *ctx;
Sujith Manoharanbc81d432014-08-22 20:39:27 +0530703 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
704
705 ath_dbg(common, CHAN_CTX, "%s: state: %s\n",
706 __func__, offchannel_state_string(sc->offchannel.state));
Sujith Manoharandfcbb3e2014-08-22 20:39:26 +0530707
708 switch (sc->offchannel.state) {
709 case ATH_OFFCHANNEL_PROBE_WAIT:
710 if (!sc->offchannel.scan_req)
711 return;
712
713 /* get first active channel context */
714 ctx = ath_chanctx_get_oper_chan(sc, true);
715 if (ctx->active) {
716 sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND;
717 ath_chanctx_switch(sc, ctx, NULL);
718 mod_timer(&sc->offchannel.timer, jiffies + HZ / 10);
719 break;
720 }
721 /* fall through */
722 case ATH_OFFCHANNEL_SUSPEND:
723 if (!sc->offchannel.scan_req)
724 return;
725
726 ath_scan_next_channel(sc);
727 break;
728 case ATH_OFFCHANNEL_ROC_START:
729 case ATH_OFFCHANNEL_ROC_WAIT:
730 ctx = ath_chanctx_get_oper_chan(sc, false);
731 sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE;
732 ath_chanctx_switch(sc, ctx, NULL);
733 break;
734 default:
735 break;
736 }
737}
Sujith Manoharan2471adf2014-08-22 20:39:29 +0530738
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +0530739static bool
740ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
741 bool powersave)
742{
743 struct ieee80211_vif *vif = avp->vif;
744 struct ieee80211_sta *sta = NULL;
745 struct ieee80211_hdr_3addr *nullfunc;
746 struct ath_tx_control txctl;
747 struct sk_buff *skb;
748 int band = sc->cur_chan->chandef.chan->band;
749
750 switch (vif->type) {
751 case NL80211_IFTYPE_STATION:
752 if (!vif->bss_conf.assoc)
753 return false;
754
755 skb = ieee80211_nullfunc_get(sc->hw, vif);
756 if (!skb)
757 return false;
758
759 nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
760 if (powersave)
761 nullfunc->frame_control |=
762 cpu_to_le16(IEEE80211_FCTL_PM);
763
764 skb_set_queue_mapping(skb, IEEE80211_AC_VO);
765 if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
766 dev_kfree_skb_any(skb);
767 return false;
768 }
769 break;
770 default:
771 return false;
772 }
773
774 memset(&txctl, 0, sizeof(txctl));
775 txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
776 txctl.sta = sta;
777 txctl.force_channel = true;
778 if (ath_tx_start(sc->hw, skb, &txctl)) {
779 ieee80211_free_txskb(sc->hw, skb);
780 return false;
781 }
782
783 return true;
784}
785
786static bool
787ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave)
788{
789 struct ath_vif *avp;
790 bool sent = false;
791
792 rcu_read_lock();
793 list_for_each_entry(avp, &sc->cur_chan->vifs, list) {
794 if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave))
795 sent = true;
796 }
797 rcu_read_unlock();
798
799 return sent;
800}
801
802static bool ath_chanctx_defer_switch(struct ath_softc *sc)
803{
804 if (sc->cur_chan == &sc->offchannel.chan)
805 return false;
806
807 switch (sc->sched.state) {
808 case ATH_CHANCTX_STATE_SWITCH:
809 return false;
810 case ATH_CHANCTX_STATE_IDLE:
811 if (!sc->cur_chan->switch_after_beacon)
812 return false;
813
814 sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
815 break;
816 default:
817 break;
818 }
819
820 return true;
821}
822
Sujith Manoharan55254ee2014-08-23 13:29:11 +0530823static void ath_offchannel_channel_change(struct ath_softc *sc)
824{
825 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
826
827 ath_dbg(common, CHAN_CTX, "%s: state: %s\n",
828 __func__, offchannel_state_string(sc->offchannel.state));
829
830 switch (sc->offchannel.state) {
831 case ATH_OFFCHANNEL_PROBE_SEND:
832 if (!sc->offchannel.scan_req)
833 return;
834
835 if (sc->cur_chan->chandef.chan !=
836 sc->offchannel.chan.chandef.chan)
837 return;
838
839 ath_scan_channel_start(sc);
840 break;
841 case ATH_OFFCHANNEL_IDLE:
842 if (!sc->offchannel.scan_req)
843 return;
844
845 ath_scan_complete(sc, false);
846 break;
847 case ATH_OFFCHANNEL_ROC_START:
848 if (sc->cur_chan != &sc->offchannel.chan)
849 break;
850
851 sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT;
852 mod_timer(&sc->offchannel.timer, jiffies +
853 msecs_to_jiffies(sc->offchannel.duration));
854 ieee80211_ready_on_channel(sc->hw);
855 break;
856 case ATH_OFFCHANNEL_ROC_DONE:
857 ath_roc_complete(sc, false);
858 break;
859 default:
860 break;
861 }
862}
863
Sujith Manoharan6d7cbd72014-08-23 13:29:10 +0530864void ath_chanctx_set_next(struct ath_softc *sc, bool force)
865{
866 struct timespec ts;
867 bool measure_time = false;
868 bool send_ps = false;
869
870 spin_lock_bh(&sc->chan_lock);
871 if (!sc->next_chan) {
872 spin_unlock_bh(&sc->chan_lock);
873 return;
874 }
875
876 if (!force && ath_chanctx_defer_switch(sc)) {
877 spin_unlock_bh(&sc->chan_lock);
878 return;
879 }
880
881 if (sc->cur_chan != sc->next_chan) {
882 sc->cur_chan->stopped = true;
883 spin_unlock_bh(&sc->chan_lock);
884
885 if (sc->next_chan == &sc->offchannel.chan) {
886 getrawmonotonic(&ts);
887 measure_time = true;
888 }
889 __ath9k_flush(sc->hw, ~0, true);
890
891 if (ath_chanctx_send_ps_frame(sc, true))
892 __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
893
894 send_ps = true;
895 spin_lock_bh(&sc->chan_lock);
896
897 if (sc->cur_chan != &sc->offchannel.chan) {
898 getrawmonotonic(&sc->cur_chan->tsf_ts);
899 sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah);
900 }
901 }
902 sc->cur_chan = sc->next_chan;
903 sc->cur_chan->stopped = false;
904 sc->next_chan = NULL;
905 sc->sched.offchannel_duration = 0;
906 if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE)
907 sc->sched.state = ATH_CHANCTX_STATE_IDLE;
908
909 spin_unlock_bh(&sc->chan_lock);
910
911 if (sc->sc_ah->chip_fullsleep ||
912 memcmp(&sc->cur_chandef, &sc->cur_chan->chandef,
913 sizeof(sc->cur_chandef))) {
914 ath_set_channel(sc);
915 if (measure_time)
916 sc->sched.channel_switch_time =
917 ath9k_hw_get_tsf_offset(&ts, NULL);
918 }
919 if (send_ps)
920 ath_chanctx_send_ps_frame(sc, false);
921
922 ath_offchannel_channel_change(sc);
923 ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH);
924}
925
Sujith Manoharan0e62f8b2014-08-23 13:29:08 +0530926static void ath_chanctx_work(struct work_struct *work)
927{
928 struct ath_softc *sc = container_of(work, struct ath_softc,
929 chanctx_work);
930 mutex_lock(&sc->mutex);
931 ath_chanctx_set_next(sc, false);
932 mutex_unlock(&sc->mutex);
933}
934
Sujith Manoharane90e3022014-08-23 13:29:20 +0530935void ath9k_offchannel_init(struct ath_softc *sc)
936{
937 struct ath_chanctx *ctx;
938 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
939 struct ieee80211_supported_band *sband;
940 struct ieee80211_channel *chan;
941 int i;
942
943 sband = &common->sbands[IEEE80211_BAND_2GHZ];
944 if (!sband->n_channels)
945 sband = &common->sbands[IEEE80211_BAND_5GHZ];
946
947 chan = &sband->channels[0];
948
949 ctx = &sc->offchannel.chan;
950 INIT_LIST_HEAD(&ctx->vifs);
951 ctx->txpower = ATH_TXPOWER_MAX;
952 cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
953
954 for (i = 0; i < ARRAY_SIZE(ctx->acq); i++)
955 INIT_LIST_HEAD(&ctx->acq[i]);
956
957 sc->offchannel.chan.offchannel = true;
958}
959
Sujith Manoharan705d0bf2014-08-23 13:29:06 +0530960void ath9k_init_channel_context(struct ath_softc *sc)
961{
962 INIT_WORK(&sc->chanctx_work, ath_chanctx_work);
963
964 setup_timer(&sc->offchannel.timer, ath_offchannel_timer,
965 (unsigned long)sc);
966 setup_timer(&sc->sched.timer, ath_chanctx_timer,
967 (unsigned long)sc);
968}
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +0530969
Sujith Manoharanea22df22014-08-23 13:29:07 +0530970void ath9k_deinit_channel_context(struct ath_softc *sc)
971{
972 cancel_work_sync(&sc->chanctx_work);
973}
974
Sujith Manoharan499afac2014-08-22 20:39:31 +0530975bool ath9k_is_chanctx_enabled(void)
976{
977 return (ath9k_use_chanctx == 1);
978}
979
Sujith Manoharan0e08b5f2014-08-23 13:29:19 +0530980/********************/
981/* Queue management */
982/********************/
983
984void ath9k_chanctx_wake_queues(struct ath_softc *sc)
985{
986 struct ath_hw *ah = sc->sc_ah;
987 int i;
988
989 if (sc->cur_chan == &sc->offchannel.chan) {
990 ieee80211_wake_queue(sc->hw,
991 sc->hw->offchannel_tx_hw_queue);
992 } else {
993 for (i = 0; i < IEEE80211_NUM_ACS; i++)
994 ieee80211_wake_queue(sc->hw,
995 sc->cur_chan->hw_queue_base + i);
996 }
997
998 if (ah->opmode == NL80211_IFTYPE_AP)
999 ieee80211_wake_queue(sc->hw, sc->hw->queues - 2);
1000}
1001
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +05301002/*****************/
1003/* P2P Powersave */
1004/*****************/
1005
1006static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
Sujith Manoharan2471adf2014-08-22 20:39:29 +05301007{
1008 struct ath_hw *ah = sc->sc_ah;
1009 s32 tsf, target_tsf;
1010
1011 if (!avp || !avp->noa.has_next_tsf)
1012 return;
1013
1014 ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer);
1015
1016 tsf = ath9k_hw_gettsf32(sc->sc_ah);
1017
1018 target_tsf = avp->noa.next_tsf;
1019 if (!avp->noa.absent)
1020 target_tsf -= ATH_P2P_PS_STOP_TIME;
1021
1022 if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
1023 target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
1024
1025 ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
1026}
1027
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +05301028static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
1029{
1030 struct ath_vif *avp = (void *)vif->drv_priv;
1031 u32 tsf;
1032
1033 if (!sc->p2p_ps_timer)
1034 return;
1035
1036 if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
1037 return;
1038
1039 sc->p2p_ps_vif = avp;
1040 tsf = ath9k_hw_gettsf32(sc->sc_ah);
1041 ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
1042 ath9k_update_p2p_ps_timer(sc, avp);
1043}
1044
Sujith Manoharan11e39a42014-08-23 19:12:15 +05301045void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
1046 struct sk_buff *skb)
1047{
1048 static const u8 noa_ie_hdr[] = {
1049 WLAN_EID_VENDOR_SPECIFIC, /* type */
1050 0, /* length */
1051 0x50, 0x6f, 0x9a, /* WFA OUI */
1052 0x09, /* P2P subtype */
1053 0x0c, /* Notice of Absence */
1054 0x00, /* LSB of little-endian len */
1055 0x00, /* MSB of little-endian len */
1056 };
1057
1058 struct ieee80211_p2p_noa_attr *noa;
1059 int noa_len, noa_desc, i = 0;
1060 u8 *hdr;
1061
1062 if (!avp->offchannel_duration && !avp->periodic_noa_duration)
1063 return;
1064
1065 noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration;
1066 noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc;
1067
1068 hdr = skb_put(skb, sizeof(noa_ie_hdr));
1069 memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr));
1070 hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2;
1071 hdr[7] = noa_len;
1072
1073 noa = (void *) skb_put(skb, noa_len);
1074 memset(noa, 0, noa_len);
1075
1076 noa->index = avp->noa_index;
1077 if (avp->periodic_noa_duration) {
1078 u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
1079
1080 noa->desc[i].count = 255;
1081 noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start);
1082 noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration);
1083 noa->desc[i].interval = cpu_to_le32(interval);
1084 i++;
1085 }
1086
1087 if (avp->offchannel_duration) {
1088 noa->desc[i].count = 1;
1089 noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start);
1090 noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration);
1091 }
1092}
1093
Sujith Manoharan2471adf2014-08-22 20:39:29 +05301094void ath9k_p2p_ps_timer(void *priv)
1095{
1096 struct ath_softc *sc = priv;
1097 struct ath_vif *avp = sc->p2p_ps_vif;
1098 struct ieee80211_vif *vif;
1099 struct ieee80211_sta *sta;
1100 struct ath_node *an;
1101 u32 tsf;
1102
1103 del_timer_sync(&sc->sched.timer);
1104 ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer);
1105 ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
1106
1107 if (!avp || avp->chanctx != sc->cur_chan)
1108 return;
1109
1110 tsf = ath9k_hw_gettsf32(sc->sc_ah);
1111 if (!avp->noa.absent)
1112 tsf += ATH_P2P_PS_STOP_TIME;
1113
1114 if (!avp->noa.has_next_tsf ||
1115 avp->noa.next_tsf - tsf > BIT(31))
1116 ieee80211_update_p2p_noa(&avp->noa, tsf);
1117
1118 ath9k_update_p2p_ps_timer(sc, avp);
1119
1120 rcu_read_lock();
1121
1122 vif = avp->vif;
1123 sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
1124 if (!sta)
1125 goto out;
1126
1127 an = (void *) sta->drv_priv;
1128 if (an->sleeping == !!avp->noa.absent)
1129 goto out;
1130
1131 an->sleeping = avp->noa.absent;
1132 if (an->sleeping)
1133 ath_tx_aggr_sleep(sta, sc, an);
1134 else
1135 ath_tx_aggr_wakeup(sc, an);
1136
1137out:
1138 rcu_read_unlock();
1139}
1140
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +05301141void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
1142 struct ieee80211_vif *vif)
1143{
1144 unsigned long flags;
1145
1146 spin_lock_bh(&sc->sc_pcu_lock);
1147 spin_lock_irqsave(&sc->sc_pm_lock, flags);
1148 if (!(sc->ps_flags & PS_BEACON_SYNC))
1149 ath9k_update_p2p_ps(sc, vif);
1150 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
1151 spin_unlock_bh(&sc->sc_pcu_lock);
1152}
1153
1154void ath9k_p2p_beacon_sync(struct ath_softc *sc)
1155{
1156 if (sc->p2p_ps_vif)
1157 ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
1158}
1159
1160void ath9k_p2p_remove_vif(struct ath_softc *sc,
1161 struct ieee80211_vif *vif)
Sujith Manoharan2471adf2014-08-22 20:39:29 +05301162{
1163 struct ath_vif *avp = (void *)vif->drv_priv;
Sujith Manoharan2471adf2014-08-22 20:39:29 +05301164
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +05301165 spin_lock_bh(&sc->sc_pcu_lock);
1166 if (avp == sc->p2p_ps_vif) {
1167 sc->p2p_ps_vif = NULL;
1168 ath9k_update_p2p_ps_timer(sc, NULL);
1169 }
1170 spin_unlock_bh(&sc->sc_pcu_lock);
Sujith Manoharan2471adf2014-08-22 20:39:29 +05301171}
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +05301172
1173int ath9k_init_p2p(struct ath_softc *sc)
1174{
1175 sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer,
1176 NULL, sc, AR_FIRST_NDP_TIMER);
1177 if (!sc->p2p_ps_timer)
1178 return -ENOMEM;
1179
1180 return 0;
1181}
1182
1183void ath9k_deinit_p2p(struct ath_softc *sc)
1184{
1185 if (sc->p2p_ps_timer)
1186 ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
1187}
1188
1189#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */