blob: 21aa09e0e825df1161a4fcca3753ca08e9632558 [file] [log] [blame]
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001/*
Sujith Manoharan5b681382011-05-17 13:36:18 +05302 * Copyright (c) 2008-2011 Atheros Communications Inc.
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07003 *
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
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070017#include <linux/nl80211.h>
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -080018#include <linux/delay.h>
Sujith394cf0a2009-02-09 13:26:54 +053019#include "ath9k.h"
Luis R. Rodriguezaf03abe2009-09-09 02:33:11 -070020#include "btcoex.h"
Luis R. Rodriguezf078f202008-08-04 00:16:41 -070021
Sujith Manoharan6dcc3442012-07-17 17:16:36 +053022static void ath9k_set_assoc_state(struct ath_softc *sc,
23 struct ieee80211_vif *vif);
24
Sven Eckelmann313eb872012-06-25 07:15:22 +020025u8 ath9k_parse_mpdudensity(u8 mpdudensity)
Sujithff37e332008-11-24 12:07:55 +053026{
27 /*
28 * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
29 * 0 for no restriction
30 * 1 for 1/4 us
31 * 2 for 1/2 us
32 * 3 for 1 us
33 * 4 for 2 us
34 * 5 for 4 us
35 * 6 for 8 us
36 * 7 for 16 us
37 */
38 switch (mpdudensity) {
39 case 0:
40 return 0;
41 case 1:
42 case 2:
43 case 3:
44 /* Our lower layer calculations limit our precision to
45 1 microsecond */
46 return 1;
47 case 4:
48 return 2;
49 case 5:
50 return 4;
51 case 6:
52 return 8;
53 case 7:
54 return 16;
55 default:
56 return 0;
57 }
58}
59
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -080060static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq)
61{
62 bool pending = false;
63
64 spin_lock_bh(&txq->axq_lock);
65
66 if (txq->axq_depth || !list_empty(&txq->axq_acq))
67 pending = true;
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -080068
69 spin_unlock_bh(&txq->axq_lock);
70 return pending;
71}
72
Mohammed Shafi Shajakhan6d79cb42011-05-19 17:40:46 +053073static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
Luis R. Rodriguez8c77a562009-09-09 21:02:34 -070074{
75 unsigned long flags;
76 bool ret;
77
Luis R. Rodriguez9ecdef42009-09-09 21:10:09 -070078 spin_lock_irqsave(&sc->sc_pm_lock, flags);
79 ret = ath9k_hw_setpower(sc->sc_ah, mode);
80 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
Luis R. Rodriguez8c77a562009-09-09 21:02:34 -070081
82 return ret;
83}
84
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -070085void ath9k_ps_wakeup(struct ath_softc *sc)
86{
Felix Fietkau898c9142010-10-12 14:02:53 +020087 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -070088 unsigned long flags;
Felix Fietkaufbb078f2010-11-03 01:36:51 +010089 enum ath9k_power_mode power_mode;
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -070090
91 spin_lock_irqsave(&sc->sc_pm_lock, flags);
92 if (++sc->ps_usecount != 1)
93 goto unlock;
94
Felix Fietkaufbb078f2010-11-03 01:36:51 +010095 power_mode = sc->sc_ah->power_mode;
Luis R. Rodriguez9ecdef42009-09-09 21:10:09 -070096 ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -070097
Felix Fietkau898c9142010-10-12 14:02:53 +020098 /*
99 * While the hardware is asleep, the cycle counters contain no
100 * useful data. Better clear them now so that they don't mess up
101 * survey data results.
102 */
Felix Fietkaufbb078f2010-11-03 01:36:51 +0100103 if (power_mode != ATH9K_PM_AWAKE) {
104 spin_lock(&common->cc_lock);
105 ath_hw_cycle_counters_update(common);
106 memset(&common->cc_survey, 0, sizeof(common->cc_survey));
Rajkumar Manoharanc9ae6ab2012-06-04 16:28:41 +0530107 memset(&common->cc_ani, 0, sizeof(common->cc_ani));
Felix Fietkaufbb078f2010-11-03 01:36:51 +0100108 spin_unlock(&common->cc_lock);
109 }
Felix Fietkau898c9142010-10-12 14:02:53 +0200110
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -0700111 unlock:
112 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
113}
114
115void ath9k_ps_restore(struct ath_softc *sc)
116{
Felix Fietkau898c9142010-10-12 14:02:53 +0200117 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkauc6c539f2011-09-14 21:24:24 +0200118 enum ath9k_power_mode mode;
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -0700119 unsigned long flags;
Sujith Manoharanad128862012-04-24 10:23:20 +0530120 bool reset;
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -0700121
122 spin_lock_irqsave(&sc->sc_pm_lock, flags);
123 if (--sc->ps_usecount != 0)
124 goto unlock;
125
Sujith Manoharanad128862012-04-24 10:23:20 +0530126 if (sc->ps_idle) {
127 ath9k_hw_setrxabort(sc->sc_ah, 1);
128 ath9k_hw_stopdmarecv(sc->sc_ah, &reset);
Felix Fietkauc6c539f2011-09-14 21:24:24 +0200129 mode = ATH9K_PM_FULL_SLEEP;
Sujith Manoharanad128862012-04-24 10:23:20 +0530130 } else if (sc->ps_enabled &&
131 !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
132 PS_WAIT_FOR_CAB |
133 PS_WAIT_FOR_PSPOLL_DATA |
Rajkumar Manoharan424749c2012-10-10 23:03:02 +0530134 PS_WAIT_FOR_TX_ACK |
135 PS_WAIT_FOR_ANI))) {
Felix Fietkauc6c539f2011-09-14 21:24:24 +0200136 mode = ATH9K_PM_NETWORK_SLEEP;
Rajkumar Manoharan08d4df42012-07-01 19:53:54 +0530137 if (ath9k_hw_btcoex_is_enabled(sc->sc_ah))
138 ath9k_btcoex_stop_gen_timer(sc);
Sujith Manoharanad128862012-04-24 10:23:20 +0530139 } else {
Felix Fietkauc6c539f2011-09-14 21:24:24 +0200140 goto unlock;
Sujith Manoharanad128862012-04-24 10:23:20 +0530141 }
Felix Fietkauc6c539f2011-09-14 21:24:24 +0200142
143 spin_lock(&common->cc_lock);
144 ath_hw_cycle_counters_update(common);
145 spin_unlock(&common->cc_lock);
146
Felix Fietkau1a8f0d392011-09-22 08:04:32 -0600147 ath9k_hw_setpower(sc->sc_ah, mode);
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -0700148
149 unlock:
150 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
151}
152
Felix Fietkau9adcf442011-09-03 01:40:26 +0200153static void __ath_cancel_work(struct ath_softc *sc)
154{
155 cancel_work_sync(&sc->paprd_work);
156 cancel_work_sync(&sc->hw_check_work);
157 cancel_delayed_work_sync(&sc->tx_complete_work);
158 cancel_delayed_work_sync(&sc->hw_pll_work);
Sujith Manoharanfad29cd2012-06-25 13:54:22 +0530159
Sujith Manoharanbf525922012-06-27 14:15:59 +0530160#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
Sujith Manoharanfad29cd2012-06-25 13:54:22 +0530161 if (ath9k_hw_mci_is_enabled(sc->sc_ah))
162 cancel_work_sync(&sc->mci_work);
Sujith Manoharanbf525922012-06-27 14:15:59 +0530163#endif
Felix Fietkau9adcf442011-09-03 01:40:26 +0200164}
165
166static void ath_cancel_work(struct ath_softc *sc)
167{
168 __ath_cancel_work(sc);
169 cancel_work_sync(&sc->hw_reset_work);
170}
171
Sujith Manoharanaf68aba2012-06-04 20:23:43 +0530172static void ath_restart_work(struct ath_softc *sc)
173{
Sujith Manoharanaf68aba2012-06-04 20:23:43 +0530174 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
175
Sujith Manoharan19c36162013-08-20 10:05:59 +0530176 if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9330(sc->sc_ah))
Sujith Manoharanaf68aba2012-06-04 20:23:43 +0530177 ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
178 msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
179
180 ath_start_rx_poll(sc, 3);
Sujith Manoharanda0d45f2012-07-17 17:16:29 +0530181 ath_start_ani(sc);
Sujith Manoharanaf68aba2012-06-04 20:23:43 +0530182}
183
John W. Linville9ebea382013-01-28 13:54:03 -0500184static bool ath_prepare_reset(struct ath_softc *sc)
Felix Fietkau9adcf442011-09-03 01:40:26 +0200185{
186 struct ath_hw *ah = sc->sc_ah;
Felix Fietkauceea2a52012-05-24 14:32:19 +0200187 bool ret = true;
Felix Fietkau9adcf442011-09-03 01:40:26 +0200188
189 ieee80211_stop_queues(sc->hw);
190
191 sc->hw_busy_count = 0;
Sujith Manoharanda0d45f2012-07-17 17:16:29 +0530192 ath_stop_ani(sc);
Rajkumar Manoharan01e18912012-03-15 05:34:27 +0530193 del_timer_sync(&sc->rx_poll_timer);
Felix Fietkau9adcf442011-09-03 01:40:26 +0200194
Felix Fietkau9adcf442011-09-03 01:40:26 +0200195 ath9k_hw_disable_interrupts(ah);
196
Felix Fietkau13815592013-01-20 18:51:53 +0100197 if (!ath_drain_all_txq(sc))
Felix Fietkau9adcf442011-09-03 01:40:26 +0200198 ret = false;
199
Felix Fietkau0a62acb2013-01-20 18:51:52 +0100200 if (!ath_stoprecv(sc))
Felix Fietkauceea2a52012-05-24 14:32:19 +0200201 ret = false;
202
Felix Fietkau9adcf442011-09-03 01:40:26 +0200203 return ret;
204}
205
206static bool ath_complete_reset(struct ath_softc *sc, bool start)
207{
208 struct ath_hw *ah = sc->sc_ah;
209 struct ath_common *common = ath9k_hw_common(ah);
Sujith Manoharan196fb862012-06-04 20:24:13 +0530210 unsigned long flags;
Felix Fietkauec303262013-10-05 14:09:30 +0200211 int i;
Felix Fietkau9adcf442011-09-03 01:40:26 +0200212
213 if (ath_startrecv(sc) != 0) {
214 ath_err(common, "Unable to restart recv logic\n");
215 return false;
216 }
217
218 ath9k_cmn_update_txpow(ah, sc->curtxpow,
219 sc->config.txpowlimit, &sc->curtxpow);
Sujith Manoharanb74713d2012-06-04 20:24:01 +0530220
221 clear_bit(SC_OP_HW_RESET, &sc->sc_flags);
Felix Fietkau72d874c2011-10-08 20:06:19 +0200222 ath9k_hw_set_interrupts(ah);
Felix Fietkau9adcf442011-09-03 01:40:26 +0200223 ath9k_hw_enable_interrupts(ah);
224
Sujith Manoharan4cb54fa2012-06-04 16:27:52 +0530225 if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) {
Sujith Manoharan196fb862012-06-04 20:24:13 +0530226 if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
227 goto work;
Felix Fietkau9adcf442011-09-03 01:40:26 +0200228
Sujith Manoharan196fb862012-06-04 20:24:13 +0530229 if (ah->opmode == NL80211_IFTYPE_STATION &&
230 test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
231 spin_lock_irqsave(&sc->sc_pm_lock, flags);
232 sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
233 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
Sujith Manoharana6768282013-05-06 10:09:03 +0530234 } else {
235 ath9k_set_beacon(sc);
Sujith Manoharan196fb862012-06-04 20:24:13 +0530236 }
237 work:
Sujith Manoharanaf68aba2012-06-04 20:23:43 +0530238 ath_restart_work(sc);
Felix Fietkauec303262013-10-05 14:09:30 +0200239
240 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
241 if (!ATH_TXQ_SETUP(sc, i))
242 continue;
243
244 spin_lock_bh(&sc->tx.txq[i].axq_lock);
245 ath_txq_schedule(sc, &sc->tx.txq[i]);
246 spin_unlock_bh(&sc->tx.txq[i].axq_lock);
247 }
Felix Fietkau9adcf442011-09-03 01:40:26 +0200248 }
249
250 ieee80211_wake_queues(sc->hw);
251
252 return true;
253}
254
Felix Fietkau13815592013-01-20 18:51:53 +0100255static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
Felix Fietkau9adcf442011-09-03 01:40:26 +0200256{
257 struct ath_hw *ah = sc->sc_ah;
258 struct ath_common *common = ath9k_hw_common(ah);
259 struct ath9k_hw_cal_data *caldata = NULL;
260 bool fastcc = true;
Felix Fietkau9adcf442011-09-03 01:40:26 +0200261 int r;
262
263 __ath_cancel_work(sc);
264
Felix Fietkau4668cce2013-01-14 16:56:46 +0100265 tasklet_disable(&sc->intr_tq);
Felix Fietkau9adcf442011-09-03 01:40:26 +0200266 spin_lock_bh(&sc->sc_pcu_lock);
267
Sujith Manoharan4cb54fa2012-06-04 16:27:52 +0530268 if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) {
Felix Fietkau9adcf442011-09-03 01:40:26 +0200269 fastcc = false;
270 caldata = &sc->caldata;
271 }
272
273 if (!hchan) {
274 fastcc = false;
Felix Fietkau9adcf442011-09-03 01:40:26 +0200275 hchan = ah->curchan;
276 }
277
John W. Linville9ebea382013-01-28 13:54:03 -0500278 if (!ath_prepare_reset(sc))
Felix Fietkau9adcf442011-09-03 01:40:26 +0200279 fastcc = false;
280
Joe Perchesd2182b62011-12-15 14:55:53 -0800281 ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n",
Sujith Manoharanfeced202012-01-30 14:21:42 +0530282 hchan->channel, IS_CHAN_HT40(hchan), fastcc);
Felix Fietkau9adcf442011-09-03 01:40:26 +0200283
284 r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
285 if (r) {
286 ath_err(common,
287 "Unable to reset channel, reset status %d\n", r);
Robert Shadef50b1cd2013-04-02 19:52:45 -0400288
289 ath9k_hw_enable_interrupts(ah);
290 ath9k_queue_reset(sc, RESET_TYPE_BB_HANG);
291
Felix Fietkau9adcf442011-09-03 01:40:26 +0200292 goto out;
293 }
294
Rajkumar Manoharane82cb032012-10-12 14:07:25 +0530295 if (ath9k_hw_mci_is_enabled(sc->sc_ah) &&
296 (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
297 ath9k_mci_set_txpower(sc, true, false);
298
Felix Fietkau9adcf442011-09-03 01:40:26 +0200299 if (!ath_complete_reset(sc, true))
300 r = -EIO;
301
302out:
303 spin_unlock_bh(&sc->sc_pcu_lock);
Felix Fietkau4668cce2013-01-14 16:56:46 +0100304 tasklet_enable(&sc->intr_tq);
305
Felix Fietkau9adcf442011-09-03 01:40:26 +0200306 return r;
307}
308
309
Sujithff37e332008-11-24 12:07:55 +0530310/*
311 * Set/change channels. If the channel is really being changed, it's done
312 * by reseting the chip. To accomplish this we must first cleanup any pending
313 * DMA, then restart stuff.
314*/
Felix Fietkau45c67f62013-10-11 23:30:58 +0200315static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chandef)
Sujithff37e332008-11-24 12:07:55 +0530316{
Felix Fietkau45c67f62013-10-11 23:30:58 +0200317 struct ath_hw *ah = sc->sc_ah;
318 struct ath_common *common = ath9k_hw_common(ah);
319 struct ieee80211_hw *hw = sc->hw;
320 struct ath9k_channel *hchan;
321 struct ieee80211_channel *chan = chandef->chan;
322 unsigned long flags;
323 bool offchannel;
324 int pos = chan->hw_value;
325 int old_pos = -1;
Luis R. Rodriguezae8d2852008-12-23 15:58:40 -0800326 int r;
Sujithff37e332008-11-24 12:07:55 +0530327
Sujith Manoharan781b14a2012-06-04 20:23:55 +0530328 if (test_bit(SC_OP_INVALID, &sc->sc_flags))
Sujithff37e332008-11-24 12:07:55 +0530329 return -EIO;
330
Felix Fietkau45c67f62013-10-11 23:30:58 +0200331 offchannel = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
Luis R. Rodriguez6a6733f2010-10-26 15:27:25 -0700332
Felix Fietkau45c67f62013-10-11 23:30:58 +0200333 if (ah->curchan)
334 old_pos = ah->curchan - &ah->channels[0];
335
336 ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n",
337 chan->center_freq, chandef->width);
338
339 /* update survey stats for the old channel before switching */
340 spin_lock_irqsave(&common->cc_lock, flags);
341 ath_update_survey_stats(sc);
342 spin_unlock_irqrestore(&common->cc_lock, flags);
343
344 ath9k_cmn_get_channel(hw, ah, chandef);
345
346 /*
347 * If the operating channel changes, change the survey in-use flags
348 * along with it.
349 * Reset the survey data for the new channel, unless we're switching
350 * back to the operating channel from an off-channel operation.
351 */
352 if (!offchannel && sc->cur_survey != &sc->survey[pos]) {
353 if (sc->cur_survey)
354 sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE;
355
356 sc->cur_survey = &sc->survey[pos];
357
358 memset(sc->cur_survey, 0, sizeof(struct survey_info));
359 sc->cur_survey->filled |= SURVEY_INFO_IN_USE;
360 } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) {
361 memset(&sc->survey[pos], 0, sizeof(struct survey_info));
362 }
363
364 hchan = &sc->sc_ah->channels[pos];
365 r = ath_reset_internal(sc, hchan);
366 if (r)
367 return r;
368
369 /*
370 * The most recent snapshot of channel->noisefloor for the old
371 * channel is only available after the hardware reset. Copy it to
372 * the survey stats now.
373 */
374 if (old_pos >= 0)
375 ath_update_survey_nf(sc, old_pos);
376
377 /*
378 * Enable radar pulse detection if on a DFS channel. Spectral
379 * scanning and radar detection can not be used concurrently.
380 */
381 if (hw->conf.radar_enabled) {
382 u32 rxfilter;
383
384 /* set HW specific DFS configuration */
385 ath9k_hw_set_radar_params(ah);
386 rxfilter = ath9k_hw_getrxfilter(ah);
387 rxfilter |= ATH9K_RX_FILTER_PHYRADAR |
388 ATH9K_RX_FILTER_PHYERR;
389 ath9k_hw_setrxfilter(ah, rxfilter);
390 ath_dbg(common, DFS, "DFS enabled at freq %d\n",
391 chan->center_freq);
392 } else {
393 /* perform spectral scan if requested. */
394 if (test_bit(SC_OP_SCANNING, &sc->sc_flags) &&
395 sc->spectral_mode == SPECTRAL_CHANSCAN)
396 ath9k_spectral_scan_trigger(hw);
397 }
398
399 return 0;
Sujithff37e332008-11-24 12:07:55 +0530400}
401
Ben Greear7e1e3862011-11-03 11:33:13 -0700402static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
403 struct ieee80211_vif *vif)
Sujithff37e332008-11-24 12:07:55 +0530404{
405 struct ath_node *an;
Sujithff37e332008-11-24 12:07:55 +0530406 an = (struct ath_node *)sta->drv_priv;
407
Sujith Manoharana145daf2012-11-28 15:08:54 +0530408 an->sc = sc;
Ben Greear7f010c92011-01-09 23:11:49 -0800409 an->sta = sta;
Ben Greear7e1e3862011-11-03 11:33:13 -0700410 an->vif = vif;
Sujith Manoharan3d4e20f2012-03-14 14:40:58 +0530411
Sujith Manoharandd5ee592013-02-04 15:38:23 +0530412 ath_tx_node_init(sc, an);
413
414 if (sta->ht_cap.ht_supported) {
Sujith9e98ac62009-07-23 15:32:34 +0530415 an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
Sujith87792ef2009-03-30 15:28:48 +0530416 sta->ht_cap.ampdu_factor);
Sujith Manoharandd5ee592013-02-04 15:38:23 +0530417 an->mpdudensity = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
Sujith87792ef2009-03-30 15:28:48 +0530418 }
Sujithff37e332008-11-24 12:07:55 +0530419}
420
421static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
422{
423 struct ath_node *an = (struct ath_node *)sta->drv_priv;
Sujith Manoharandd5ee592013-02-04 15:38:23 +0530424 ath_tx_node_cleanup(sc, an);
Sujithff37e332008-11-24 12:07:55 +0530425}
426
Sujith55624202010-01-08 10:36:02 +0530427void ath9k_tasklet(unsigned long data)
Sujithff37e332008-11-24 12:07:55 +0530428{
429 struct ath_softc *sc = (struct ath_softc *)data;
Luis R. Rodriguezaf03abe2009-09-09 02:33:11 -0700430 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700431 struct ath_common *common = ath9k_hw_common(ah);
Rajkumar Manoharan124b9792012-07-17 17:16:42 +0530432 enum ath_reset_type type;
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530433 unsigned long flags;
Sujith17d79042009-02-09 13:27:03 +0530434 u32 status = sc->intrstatus;
Felix Fietkaub5c804752010-04-15 17:38:48 -0400435 u32 rxmask;
Sujithff37e332008-11-24 12:07:55 +0530436
Felix Fietkaue3927002011-09-14 21:23:01 +0200437 ath9k_ps_wakeup(sc);
438 spin_lock(&sc->sc_pcu_lock);
439
Rajkumar Manoharana4d86d92011-05-20 17:52:10 +0530440 if ((status & ATH9K_INT_FATAL) ||
441 (status & ATH9K_INT_BB_WATCHDOG)) {
Felix Fietkau030d6292011-10-07 02:28:13 +0200442
443 if (status & ATH9K_INT_FATAL)
444 type = RESET_TYPE_FATAL_INT;
445 else
446 type = RESET_TYPE_BB_WATCHDOG;
447
Rajkumar Manoharan124b9792012-07-17 17:16:42 +0530448 ath9k_queue_reset(sc, type);
Sujith Manoharanc6cc47b2013-09-16 10:37:00 +0530449
450 /*
451 * Increment the ref. counter here so that
452 * interrupts are enabled in the reset routine.
453 */
454 atomic_inc(&ah->intr_ref_cnt);
455 ath_dbg(common, ANY, "FATAL: Skipping interrupts\n");
Felix Fietkaue3927002011-09-14 21:23:01 +0200456 goto out;
Sujithff37e332008-11-24 12:07:55 +0530457 }
458
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530459 spin_lock_irqsave(&sc->sc_pm_lock, flags);
Rajkumar Manoharan4105f802011-05-06 18:27:47 +0530460 if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
461 /*
462 * TSF sync does not look correct; remain awake to sync with
463 * the next Beacon.
464 */
Joe Perchesd2182b62011-12-15 14:55:53 -0800465 ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n");
Rajkumar Manoharane8fe7332011-08-05 18:59:41 +0530466 sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
Rajkumar Manoharan4105f802011-05-06 18:27:47 +0530467 }
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530468 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
Rajkumar Manoharan4105f802011-05-06 18:27:47 +0530469
Felix Fietkaub5c804752010-04-15 17:38:48 -0400470 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
471 rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
472 ATH9K_INT_RXORN);
473 else
474 rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
475
476 if (status & rxmask) {
Felix Fietkaub5c804752010-04-15 17:38:48 -0400477 /* Check for high priority Rx first */
478 if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
479 (status & ATH9K_INT_RXHP))
480 ath_rx_tasklet(sc, 0, true);
481
482 ath_rx_tasklet(sc, 0, false);
Sujith063d8be2009-03-30 15:28:49 +0530483 }
484
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400485 if (status & ATH9K_INT_TX) {
486 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
487 ath_tx_edma_tasklet(sc);
488 else
489 ath_tx_tasklet(sc);
490 }
Sujith063d8be2009-03-30 15:28:49 +0530491
Sujith Manoharan56ca0db2012-02-22 12:40:32 +0530492 ath9k_btcoex_handle_interrupt(sc, status);
Mohammed Shafi Shajakhan19686dd2011-11-30 10:41:28 +0530493
Sujithff37e332008-11-24 12:07:55 +0530494 /* re-enable hardware interrupt */
Felix Fietkau4df30712010-11-08 20:54:47 +0100495 ath9k_hw_enable_interrupts(ah);
Sujith Manoharanc6cc47b2013-09-16 10:37:00 +0530496out:
Senthil Balasubramanian52671e42010-12-23 21:06:57 +0530497 spin_unlock(&sc->sc_pcu_lock);
Vasanthakumar Thiagarajan153e0802009-05-15 02:47:16 -0400498 ath9k_ps_restore(sc);
Sujithff37e332008-11-24 12:07:55 +0530499}
500
Gabor Juhos6baff7f2009-01-14 20:17:06 +0100501irqreturn_t ath_isr(int irq, void *dev)
Sujithff37e332008-11-24 12:07:55 +0530502{
Sujith063d8be2009-03-30 15:28:49 +0530503#define SCHED_INTR ( \
504 ATH9K_INT_FATAL | \
Rajkumar Manoharana4d86d92011-05-20 17:52:10 +0530505 ATH9K_INT_BB_WATCHDOG | \
Sujith063d8be2009-03-30 15:28:49 +0530506 ATH9K_INT_RXORN | \
507 ATH9K_INT_RXEOL | \
508 ATH9K_INT_RX | \
Felix Fietkaub5c804752010-04-15 17:38:48 -0400509 ATH9K_INT_RXLP | \
510 ATH9K_INT_RXHP | \
Sujith063d8be2009-03-30 15:28:49 +0530511 ATH9K_INT_TX | \
512 ATH9K_INT_BMISS | \
513 ATH9K_INT_CST | \
Vasanthakumar Thiagarajanebb8e1d2009-09-01 17:46:32 +0530514 ATH9K_INT_TSFOOR | \
Mohammed Shafi Shajakhan40dc5392011-11-30 10:41:18 +0530515 ATH9K_INT_GENTIMER | \
516 ATH9K_INT_MCI)
Sujith063d8be2009-03-30 15:28:49 +0530517
Sujithff37e332008-11-24 12:07:55 +0530518 struct ath_softc *sc = dev;
Sujithcbe61d82009-02-09 13:27:12 +0530519 struct ath_hw *ah = sc->sc_ah;
Felix Fietkaub5bfc562010-10-08 22:13:53 +0200520 struct ath_common *common = ath9k_hw_common(ah);
Sujithff37e332008-11-24 12:07:55 +0530521 enum ath9k_int status;
522 bool sched = false;
523
Sujith063d8be2009-03-30 15:28:49 +0530524 /*
525 * The hardware is not ready/present, don't
526 * touch anything. Note this can happen early
527 * on if the IRQ is shared.
528 */
Sujith Manoharan781b14a2012-06-04 20:23:55 +0530529 if (test_bit(SC_OP_INVALID, &sc->sc_flags))
Sujith063d8be2009-03-30 15:28:49 +0530530 return IRQ_NONE;
Sujithff37e332008-11-24 12:07:55 +0530531
Sujith063d8be2009-03-30 15:28:49 +0530532 /* shared irq, not for us */
Sujithff37e332008-11-24 12:07:55 +0530533
Vasanthakumar Thiagarajan153e0802009-05-15 02:47:16 -0400534 if (!ath9k_hw_intrpend(ah))
Sujith063d8be2009-03-30 15:28:49 +0530535 return IRQ_NONE;
Sujithff37e332008-11-24 12:07:55 +0530536
Felix Fietkauf41a9b32012-08-08 16:25:03 +0200537 if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) {
538 ath9k_hw_kill_interrupts(ah);
Sujith Manoharanb74713d2012-06-04 20:24:01 +0530539 return IRQ_HANDLED;
Felix Fietkauf41a9b32012-08-08 16:25:03 +0200540 }
Sujith Manoharanb74713d2012-06-04 20:24:01 +0530541
Sujith063d8be2009-03-30 15:28:49 +0530542 /*
543 * Figure out the reason(s) for the interrupt. Note
544 * that the hal returns a pseudo-ISR that may include
545 * bits we haven't explicitly enabled so we mask the
546 * value to insure we only process bits we requested.
547 */
548 ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
Pavel Roskin30691682010-03-31 18:05:31 -0400549 status &= ah->imask; /* discard unasked-for bits */
Sujith063d8be2009-03-30 15:28:49 +0530550
551 /*
552 * If there are no status bits set, then this interrupt was not
553 * for me (should have been caught above).
554 */
Vasanthakumar Thiagarajan153e0802009-05-15 02:47:16 -0400555 if (!status)
Sujith063d8be2009-03-30 15:28:49 +0530556 return IRQ_NONE;
Sujith063d8be2009-03-30 15:28:49 +0530557
558 /* Cache the status */
559 sc->intrstatus = status;
560
561 if (status & SCHED_INTR)
562 sched = true;
563
564 /*
565 * If a FATAL or RXORN interrupt is received, we have to reset the
566 * chip immediately.
567 */
Felix Fietkaub5c804752010-04-15 17:38:48 -0400568 if ((status & ATH9K_INT_FATAL) || ((status & ATH9K_INT_RXORN) &&
569 !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)))
Sujith063d8be2009-03-30 15:28:49 +0530570 goto chip_reset;
571
Luis R. Rodriguez08578b82010-05-13 13:33:44 -0400572 if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
573 (status & ATH9K_INT_BB_WATCHDOG)) {
Felix Fietkaub5bfc562010-10-08 22:13:53 +0200574
575 spin_lock(&common->cc_lock);
576 ath_hw_cycle_counters_update(common);
Luis R. Rodriguez08578b82010-05-13 13:33:44 -0400577 ar9003_hw_bb_watchdog_dbg_info(ah);
Felix Fietkaub5bfc562010-10-08 22:13:53 +0200578 spin_unlock(&common->cc_lock);
579
Luis R. Rodriguez08578b82010-05-13 13:33:44 -0400580 goto chip_reset;
581 }
Rajkumar Manoharanca90ef42012-11-20 18:29:59 +0530582#ifdef CONFIG_PM_SLEEP
583 if (status & ATH9K_INT_BMISS) {
584 if (atomic_read(&sc->wow_sleep_proc_intr) == 0) {
585 ath_dbg(common, ANY, "during WoW we got a BMISS\n");
586 atomic_inc(&sc->wow_got_bmiss_intr);
587 atomic_dec(&sc->wow_sleep_proc_intr);
588 }
589 }
590#endif
Sujith063d8be2009-03-30 15:28:49 +0530591 if (status & ATH9K_INT_SWBA)
592 tasklet_schedule(&sc->bcon_tasklet);
593
594 if (status & ATH9K_INT_TXURN)
595 ath9k_hw_updatetxtriglevel(ah, true);
596
Rajkumar Manoharan0682c9b2011-08-13 10:28:09 +0530597 if (status & ATH9K_INT_RXEOL) {
598 ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
Felix Fietkau72d874c2011-10-08 20:06:19 +0200599 ath9k_hw_set_interrupts(ah);
Felix Fietkaub5c804752010-04-15 17:38:48 -0400600 }
601
Vasanthakumar Thiagarajan153e0802009-05-15 02:47:16 -0400602 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
603 if (status & ATH9K_INT_TIM_TIMER) {
Luis R. Rodriguezff9f0b62010-12-07 15:13:22 -0800604 if (ATH_DBG_WARN_ON_ONCE(sc->ps_idle))
605 goto chip_reset;
Sujith063d8be2009-03-30 15:28:49 +0530606 /* Clear RxAbort bit so that we can
607 * receive frames */
Luis R. Rodriguez9ecdef42009-09-09 21:10:09 -0700608 ath9k_setpower(sc, ATH9K_PM_AWAKE);
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530609 spin_lock(&sc->sc_pm_lock);
Vasanthakumar Thiagarajan153e0802009-05-15 02:47:16 -0400610 ath9k_hw_setrxabort(sc->sc_ah, 0);
Sujith1b04b932010-01-08 10:36:05 +0530611 sc->ps_flags |= PS_WAIT_FOR_BEACON;
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530612 spin_unlock(&sc->sc_pm_lock);
Sujith063d8be2009-03-30 15:28:49 +0530613 }
Sujith063d8be2009-03-30 15:28:49 +0530614
615chip_reset:
616
Sujith817e11d2008-12-07 21:42:44 +0530617 ath_debug_stat_interrupt(sc, status);
618
Sujithff37e332008-11-24 12:07:55 +0530619 if (sched) {
Felix Fietkau4df30712010-11-08 20:54:47 +0100620 /* turn off every interrupt */
621 ath9k_hw_disable_interrupts(ah);
Sujithff37e332008-11-24 12:07:55 +0530622 tasklet_schedule(&sc->intr_tq);
623 }
624
625 return IRQ_HANDLED;
Sujith063d8be2009-03-30 15:28:49 +0530626
627#undef SCHED_INTR
Sujithff37e332008-11-24 12:07:55 +0530628}
629
Felix Fietkau13815592013-01-20 18:51:53 +0100630static int ath_reset(struct ath_softc *sc)
Sujithff37e332008-11-24 12:07:55 +0530631{
Felix Fietkauec303262013-10-05 14:09:30 +0200632 int r;
Sujithff37e332008-11-24 12:07:55 +0530633
Felix Fietkau783cd012011-01-21 18:52:38 +0100634 ath9k_ps_wakeup(sc);
Felix Fietkau13815592013-01-20 18:51:53 +0100635 r = ath_reset_internal(sc, NULL);
Felix Fietkau783cd012011-01-21 18:52:38 +0100636 ath9k_ps_restore(sc);
Sujith2ab81d42009-12-14 16:34:56 +0530637
Luis R. Rodriguezae8d2852008-12-23 15:58:40 -0800638 return r;
Sujithff37e332008-11-24 12:07:55 +0530639}
640
Rajkumar Manoharan124b9792012-07-17 17:16:42 +0530641void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
642{
643#ifdef CONFIG_ATH9K_DEBUGFS
644 RESET_STAT_INC(sc, type);
645#endif
646 set_bit(SC_OP_HW_RESET, &sc->sc_flags);
647 ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
648}
649
Felix Fietkau236de512011-09-03 01:40:25 +0200650void ath_reset_work(struct work_struct *work)
651{
652 struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
653
Felix Fietkau13815592013-01-20 18:51:53 +0100654 ath_reset(sc);
Felix Fietkau236de512011-09-03 01:40:25 +0200655}
656
Sujithff37e332008-11-24 12:07:55 +0530657/**********************/
658/* mac80211 callbacks */
659/**********************/
660
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700661static int ath9k_start(struct ieee80211_hw *hw)
662{
Felix Fietkau9ac586152011-01-24 19:23:18 +0100663 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezaf03abe2009-09-09 02:33:11 -0700664 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700665 struct ath_common *common = ath9k_hw_common(ah);
Karl Beldan675a0b02013-03-25 16:26:57 +0100666 struct ieee80211_channel *curchan = hw->conf.chandef.chan;
Sujithff37e332008-11-24 12:07:55 +0530667 struct ath9k_channel *init_channel;
Vasanthakumar Thiagarajan82880a72009-06-13 14:50:24 +0530668 int r;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700669
Joe Perchesd2182b62011-12-15 14:55:53 -0800670 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -0800671 "Starting driver with initial channel: %d MHz\n",
672 curchan->center_freq);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700673
Felix Fietkauf62d8162011-03-25 17:43:41 +0100674 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +0530675 mutex_lock(&sc->mutex);
676
Felix Fietkau2297f1c2013-10-11 23:30:57 +0200677 init_channel = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700678
Sujithff37e332008-11-24 12:07:55 +0530679 /* Reset SERDES registers */
Stanislaw Gruszka84c87dc2011-08-05 13:10:32 +0200680 ath9k_hw_configpcipowersave(ah, false);
Sujithff37e332008-11-24 12:07:55 +0530681
682 /*
683 * The basic interface to setting the hardware in a good
684 * state is ``reset''. On return the hardware is known to
685 * be powered up and with interrupts disabled. This must
686 * be followed by initialization of the appropriate bits
687 * and then setup of the interrupt mask.
688 */
Luis R. Rodriguez4bdd1e92010-10-26 15:27:24 -0700689 spin_lock_bh(&sc->sc_pcu_lock);
Felix Fietkauc0c11742011-11-16 13:08:41 +0100690
691 atomic_set(&ah->intr_ref_cnt, -1);
692
Felix Fietkau20bd2a02010-07-31 00:12:00 +0200693 r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
Luis R. Rodriguezae8d2852008-12-23 15:58:40 -0800694 if (r) {
Joe Perches38002762010-12-02 19:12:36 -0800695 ath_err(common,
696 "Unable to reset hardware; reset status %d (freq %u MHz)\n",
697 r, curchan->center_freq);
Felix Fietkauceb26a62012-10-03 21:07:51 +0200698 ah->reset_power_on = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700699 }
Sujithff37e332008-11-24 12:07:55 +0530700
Sujithff37e332008-11-24 12:07:55 +0530701 /* Setup our intr mask. */
Felix Fietkaub5c804752010-04-15 17:38:48 -0400702 ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
703 ATH9K_INT_RXORN | ATH9K_INT_FATAL |
704 ATH9K_INT_GLOBAL;
705
706 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
Luis R. Rodriguez08578b82010-05-13 13:33:44 -0400707 ah->imask |= ATH9K_INT_RXHP |
708 ATH9K_INT_RXLP |
709 ATH9K_INT_BB_WATCHDOG;
Felix Fietkaub5c804752010-04-15 17:38:48 -0400710 else
711 ah->imask |= ATH9K_INT_RX;
Sujithff37e332008-11-24 12:07:55 +0530712
Felix Fietkau364734f2010-09-14 20:22:44 +0200713 ah->imask |= ATH9K_INT_GTT;
Sujithff37e332008-11-24 12:07:55 +0530714
Luis R. Rodriguezaf03abe2009-09-09 02:33:11 -0700715 if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
Pavel Roskin30691682010-03-31 18:05:31 -0400716 ah->imask |= ATH9K_INT_CST;
Sujithff37e332008-11-24 12:07:55 +0530717
Sujith Manoharane270e772012-06-04 16:27:19 +0530718 ath_mci_enable(sc);
Mohammed Shafi Shajakhan40dc5392011-11-30 10:41:18 +0530719
Sujith Manoharan781b14a2012-06-04 20:23:55 +0530720 clear_bit(SC_OP_INVALID, &sc->sc_flags);
Rajkumar Manoharan5f841b42010-10-27 18:31:15 +0530721 sc->sc_ah->is_monitoring = false;
Sujithff37e332008-11-24 12:07:55 +0530722
Felix Fietkauceb26a62012-10-03 21:07:51 +0200723 if (!ath_complete_reset(sc, false))
724 ah->reset_power_on = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700725
Felix Fietkauc0c11742011-11-16 13:08:41 +0100726 if (ah->led_pin >= 0) {
727 ath9k_hw_cfg_output(ah, ah->led_pin,
728 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
729 ath9k_hw_set_gpio(ah, ah->led_pin, 0);
730 }
731
732 /*
733 * Reset key cache to sane defaults (all entries cleared) instead of
734 * semi-random values after suspend/resume.
735 */
736 ath9k_cmn_init_crypto(sc->sc_ah);
737
Felix Fietkau9adcf442011-09-03 01:40:26 +0200738 spin_unlock_bh(&sc->sc_pcu_lock);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -0400739
Sujith141b38b2009-02-04 08:10:07 +0530740 mutex_unlock(&sc->mutex);
741
Felix Fietkauf62d8162011-03-25 17:43:41 +0100742 ath9k_ps_restore(sc);
743
Felix Fietkauceb26a62012-10-03 21:07:51 +0200744 return 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700745}
746
Thomas Huehn36323f82012-07-23 21:33:42 +0200747static void ath9k_tx(struct ieee80211_hw *hw,
748 struct ieee80211_tx_control *control,
749 struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700750{
Felix Fietkau9ac586152011-01-24 19:23:18 +0100751 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700752 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith528f0c62008-10-29 10:14:26 +0530753 struct ath_tx_control txctl;
Benoit Papillault1bc14882009-11-24 15:49:18 +0100754 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530755 unsigned long flags;
Sujith528f0c62008-10-29 10:14:26 +0530756
Gabor Juhos96148322009-07-24 17:27:21 +0200757 if (sc->ps_enabled) {
Jouni Malinendc8c4582009-05-19 17:01:42 +0300758 /*
759 * mac80211 does not set PM field for normal data frames, so we
760 * need to update that based on the current PS mode.
761 */
762 if (ieee80211_is_data(hdr->frame_control) &&
763 !ieee80211_is_nullfunc(hdr->frame_control) &&
764 !ieee80211_has_pm(hdr->frame_control)) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800765 ath_dbg(common, PS,
Joe Perches226afe62010-12-02 19:12:37 -0800766 "Add PM=1 for a TX frame while in PS mode\n");
Jouni Malinendc8c4582009-05-19 17:01:42 +0300767 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
768 }
769 }
770
Sujith Manoharanad128862012-04-24 10:23:20 +0530771 if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP)) {
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300772 /*
773 * We are using PS-Poll and mac80211 can request TX while in
774 * power save mode. Need to wake up hardware for the TX to be
775 * completed and if needed, also for RX of buffered frames.
776 */
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300777 ath9k_ps_wakeup(sc);
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530778 spin_lock_irqsave(&sc->sc_pm_lock, flags);
Vasanthakumar Thiagarajanfdf76622010-05-17 18:57:55 -0700779 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
780 ath9k_hw_setrxabort(sc->sc_ah, 0);
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300781 if (ieee80211_is_pspoll(hdr->frame_control)) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800782 ath_dbg(common, PS,
Joe Perches226afe62010-12-02 19:12:37 -0800783 "Sending PS-Poll to pick a buffered frame\n");
Sujith1b04b932010-01-08 10:36:05 +0530784 sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA;
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300785 } else {
Joe Perchesd2182b62011-12-15 14:55:53 -0800786 ath_dbg(common, PS, "Wake up to complete TX\n");
Sujith1b04b932010-01-08 10:36:05 +0530787 sc->ps_flags |= PS_WAIT_FOR_TX_ACK;
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300788 }
789 /*
790 * The actual restore operation will happen only after
Sujith Manoharanad128862012-04-24 10:23:20 +0530791 * the ps_flags bit is cleared. We are just dropping
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300792 * the ps_usecount here.
793 */
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530794 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300795 ath9k_ps_restore(sc);
796 }
797
Sujith Manoharanad128862012-04-24 10:23:20 +0530798 /*
799 * Cannot tx while the hardware is in full sleep, it first needs a full
800 * chip reset to recover from that
801 */
802 if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP)) {
803 ath_err(common, "TX while HW is in FULL_SLEEP mode\n");
804 goto exit;
805 }
806
Sujith528f0c62008-10-29 10:14:26 +0530807 memset(&txctl, 0, sizeof(struct ath_tx_control));
Felix Fietkau066dae92010-11-07 14:59:39 +0100808 txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)];
Thomas Huehn36323f82012-07-23 21:33:42 +0200809 txctl.sta = control->sta;
Sujith528f0c62008-10-29 10:14:26 +0530810
Joe Perchesd2182b62011-12-15 14:55:53 -0800811 ath_dbg(common, XMIT, "transmitting packet, skb: %p\n", skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700812
Jouni Malinenc52f33d2009-03-03 19:23:29 +0200813 if (ath_tx_start(hw, skb, &txctl) != 0) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800814 ath_dbg(common, XMIT, "TX failed\n");
Ben Greeara5a0bca2012-04-03 09:16:55 -0700815 TX_STAT_INC(txctl.txq->axq_qnum, txfailed);
Sujith528f0c62008-10-29 10:14:26 +0530816 goto exit;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700817 }
818
Johannes Berg7bb45682011-02-24 14:42:06 +0100819 return;
Sujith528f0c62008-10-29 10:14:26 +0530820exit:
Felix Fietkau249ee722012-10-03 21:07:52 +0200821 ieee80211_free_txskb(hw, skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700822}
823
824static void ath9k_stop(struct ieee80211_hw *hw)
825{
Felix Fietkau9ac586152011-01-24 19:23:18 +0100826 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezaf03abe2009-09-09 02:33:11 -0700827 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700828 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkauc0c11742011-11-16 13:08:41 +0100829 bool prev_idle;
Sujith9c84b792008-10-29 10:17:13 +0530830
Sujith4c483812009-08-18 10:51:52 +0530831 mutex_lock(&sc->mutex);
832
Felix Fietkau9adcf442011-09-03 01:40:26 +0200833 ath_cancel_work(sc);
Rajkumar Manoharan01e18912012-03-15 05:34:27 +0530834 del_timer_sync(&sc->rx_poll_timer);
Luis R. Rodriguezc94dbff2009-07-27 11:53:04 -0700835
Sujith Manoharan781b14a2012-06-04 20:23:55 +0530836 if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800837 ath_dbg(common, ANY, "Device not present\n");
Sujith4c483812009-08-18 10:51:52 +0530838 mutex_unlock(&sc->mutex);
Sujith9c84b792008-10-29 10:17:13 +0530839 return;
840 }
841
Sujith3867cf62009-12-23 20:03:27 -0500842 /* Ensure HW is awake when we try to shut it down. */
843 ath9k_ps_wakeup(sc);
844
Luis R. Rodriguez6a6733f2010-10-26 15:27:25 -0700845 spin_lock_bh(&sc->sc_pcu_lock);
846
Stanislaw Gruszka203043f2011-01-25 14:08:40 +0100847 /* prevent tasklets to enable interrupts once we disable them */
848 ah->imask &= ~ATH9K_INT_GLOBAL;
849
Sujithff37e332008-11-24 12:07:55 +0530850 /* make sure h/w will not generate any interrupt
851 * before setting the invalid flag. */
Felix Fietkau4df30712010-11-08 20:54:47 +0100852 ath9k_hw_disable_interrupts(ah);
Sujithff37e332008-11-24 12:07:55 +0530853
Luis R. Rodriguez6a6733f2010-10-26 15:27:25 -0700854 spin_unlock_bh(&sc->sc_pcu_lock);
855
Stanislaw Gruszka203043f2011-01-25 14:08:40 +0100856 /* we can now sync irq and kill any running tasklets, since we already
857 * disabled interrupts and not holding a spin lock */
858 synchronize_irq(sc->irq);
859 tasklet_kill(&sc->intr_tq);
860 tasklet_kill(&sc->bcon_tasklet);
861
Felix Fietkauc0c11742011-11-16 13:08:41 +0100862 prev_idle = sc->ps_idle;
863 sc->ps_idle = true;
864
865 spin_lock_bh(&sc->sc_pcu_lock);
866
867 if (ah->led_pin >= 0) {
868 ath9k_hw_set_gpio(ah, ah->led_pin, 1);
869 ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
870 }
871
John W. Linville9ebea382013-01-28 13:54:03 -0500872 ath_prepare_reset(sc);
Felix Fietkauc0c11742011-11-16 13:08:41 +0100873
874 if (sc->rx.frag) {
875 dev_kfree_skb_any(sc->rx.frag);
876 sc->rx.frag = NULL;
877 }
878
879 if (!ah->curchan)
Felix Fietkau2297f1c2013-10-11 23:30:57 +0200880 ah->curchan = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef);
Felix Fietkauc0c11742011-11-16 13:08:41 +0100881
882 ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
883 ath9k_hw_phy_disable(ah);
884
885 ath9k_hw_configpcipowersave(ah, true);
886
887 spin_unlock_bh(&sc->sc_pcu_lock);
888
Sujith3867cf62009-12-23 20:03:27 -0500889 ath9k_ps_restore(sc);
890
Sujith Manoharan781b14a2012-06-04 20:23:55 +0530891 set_bit(SC_OP_INVALID, &sc->sc_flags);
Felix Fietkauc0c11742011-11-16 13:08:41 +0100892 sc->ps_idle = prev_idle;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700893
Sujith141b38b2009-02-04 08:10:07 +0530894 mutex_unlock(&sc->mutex);
895
Joe Perchesd2182b62011-12-15 14:55:53 -0800896 ath_dbg(common, CONFIG, "Driver halt\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700897}
898
Felix Fietkauc648ecb2013-10-11 23:31:00 +0200899static bool ath9k_uses_beacons(int type)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700900{
Ben Greear48014162011-01-15 19:13:48 +0000901 switch (type) {
Johannes Berg05c914f2008-09-11 00:01:58 +0200902 case NL80211_IFTYPE_AP:
Ben Greear48014162011-01-15 19:13:48 +0000903 case NL80211_IFTYPE_ADHOC:
Pat Erley9cb54122009-03-20 22:59:59 -0400904 case NL80211_IFTYPE_MESH_POINT:
Ben Greear48014162011-01-15 19:13:48 +0000905 return true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700906 default:
Ben Greear48014162011-01-15 19:13:48 +0000907 return false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700908 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700909}
910
Ben Greear48014162011-01-15 19:13:48 +0000911static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
912{
913 struct ath9k_vif_iter_data *iter_data = data;
914 int i;
915
Felix Fietkauab11bb22013-04-16 12:51:57 +0200916 if (iter_data->has_hw_macaddr) {
Ben Greear48014162011-01-15 19:13:48 +0000917 for (i = 0; i < ETH_ALEN; i++)
918 iter_data->mask[i] &=
919 ~(iter_data->hw_macaddr[i] ^ mac[i]);
Felix Fietkauab11bb22013-04-16 12:51:57 +0200920 } else {
921 memcpy(iter_data->hw_macaddr, mac, ETH_ALEN);
922 iter_data->has_hw_macaddr = true;
923 }
Ben Greear48014162011-01-15 19:13:48 +0000924
925 switch (vif->type) {
926 case NL80211_IFTYPE_AP:
927 iter_data->naps++;
928 break;
929 case NL80211_IFTYPE_STATION:
930 iter_data->nstations++;
931 break;
932 case NL80211_IFTYPE_ADHOC:
933 iter_data->nadhocs++;
934 break;
935 case NL80211_IFTYPE_MESH_POINT:
936 iter_data->nmeshes++;
937 break;
938 case NL80211_IFTYPE_WDS:
939 iter_data->nwds++;
940 break;
941 default:
Ben Greear48014162011-01-15 19:13:48 +0000942 break;
943 }
944}
945
Sujith Manoharan6dcc3442012-07-17 17:16:36 +0530946static void ath9k_sta_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
947{
948 struct ath_softc *sc = data;
949 struct ath_vif *avp = (void *)vif->drv_priv;
950
951 if (vif->type != NL80211_IFTYPE_STATION)
952 return;
953
954 if (avp->primary_sta_vif)
955 ath9k_set_assoc_state(sc, vif);
956}
957
Ben Greear48014162011-01-15 19:13:48 +0000958/* Called with sc->mutex held. */
959void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
960 struct ieee80211_vif *vif,
961 struct ath9k_vif_iter_data *iter_data)
962{
Felix Fietkau9ac586152011-01-24 19:23:18 +0100963 struct ath_softc *sc = hw->priv;
Ben Greear48014162011-01-15 19:13:48 +0000964 struct ath_hw *ah = sc->sc_ah;
965 struct ath_common *common = ath9k_hw_common(ah);
Ben Greear48014162011-01-15 19:13:48 +0000966
967 /*
Mathy Vanhoef657eb172013-11-28 12:21:45 +0100968 * Pick the MAC address of the first interface as the new hardware
969 * MAC address. The hardware will use it together with the BSSID mask
970 * when matching addresses.
Ben Greear48014162011-01-15 19:13:48 +0000971 */
972 memset(iter_data, 0, sizeof(*iter_data));
Ben Greear48014162011-01-15 19:13:48 +0000973 memset(&iter_data->mask, 0xff, ETH_ALEN);
974
975 if (vif)
976 ath9k_vif_iter(iter_data, vif->addr, vif);
977
978 /* Get list of all active MAC addresses */
Johannes Berg8b2c9822012-11-06 20:23:30 +0100979 ieee80211_iterate_active_interfaces_atomic(
980 sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
981 ath9k_vif_iter, iter_data);
Felix Fietkauab11bb22013-04-16 12:51:57 +0200982
983 memcpy(common->macaddr, iter_data->hw_macaddr, ETH_ALEN);
Ben Greear48014162011-01-15 19:13:48 +0000984}
985
986/* Called with sc->mutex held. */
987static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
988 struct ieee80211_vif *vif)
989{
Felix Fietkau9ac586152011-01-24 19:23:18 +0100990 struct ath_softc *sc = hw->priv;
Ben Greear48014162011-01-15 19:13:48 +0000991 struct ath_hw *ah = sc->sc_ah;
992 struct ath_common *common = ath9k_hw_common(ah);
993 struct ath9k_vif_iter_data iter_data;
Sujith Manoharan6dcc3442012-07-17 17:16:36 +0530994 enum nl80211_iftype old_opmode = ah->opmode;
Ben Greear48014162011-01-15 19:13:48 +0000995
996 ath9k_calculate_iter_data(hw, vif, &iter_data);
997
Ben Greear48014162011-01-15 19:13:48 +0000998 memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
999 ath_hw_setbssidmask(common);
1000
Ben Greear48014162011-01-15 19:13:48 +00001001 if (iter_data.naps > 0) {
Sujith Manoharan60ca9f82012-07-17 17:15:37 +05301002 ath9k_hw_set_tsfadjust(ah, true);
Ben Greear48014162011-01-15 19:13:48 +00001003 ah->opmode = NL80211_IFTYPE_AP;
1004 } else {
Sujith Manoharan60ca9f82012-07-17 17:15:37 +05301005 ath9k_hw_set_tsfadjust(ah, false);
Ben Greear48014162011-01-15 19:13:48 +00001006
Javier Cardonafd5999c2011-05-03 16:57:19 -07001007 if (iter_data.nmeshes)
1008 ah->opmode = NL80211_IFTYPE_MESH_POINT;
1009 else if (iter_data.nwds)
Ben Greear48014162011-01-15 19:13:48 +00001010 ah->opmode = NL80211_IFTYPE_AP;
1011 else if (iter_data.nadhocs)
1012 ah->opmode = NL80211_IFTYPE_ADHOC;
1013 else
1014 ah->opmode = NL80211_IFTYPE_STATION;
1015 }
1016
Sujith Manoharandf35d292012-07-17 17:15:43 +05301017 ath9k_hw_setopmode(ah);
1018
Felix Fietkau198823f2012-06-15 15:25:25 +02001019 if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0)
Ben Greear48014162011-01-15 19:13:48 +00001020 ah->imask |= ATH9K_INT_TSFOOR;
Felix Fietkau198823f2012-06-15 15:25:25 +02001021 else
Ben Greear48014162011-01-15 19:13:48 +00001022 ah->imask &= ~ATH9K_INT_TSFOOR;
Ben Greear48014162011-01-15 19:13:48 +00001023
Felix Fietkau72d874c2011-10-08 20:06:19 +02001024 ath9k_hw_set_interrupts(ah);
Sujith Manoharan6dcc3442012-07-17 17:16:36 +05301025
1026 /*
1027 * If we are changing the opmode to STATION,
1028 * a beacon sync needs to be done.
1029 */
1030 if (ah->opmode == NL80211_IFTYPE_STATION &&
1031 old_opmode == NL80211_IFTYPE_AP &&
1032 test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
Johannes Berg8b2c9822012-11-06 20:23:30 +01001033 ieee80211_iterate_active_interfaces_atomic(
1034 sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
1035 ath9k_sta_vif_iter, sc);
Sujith Manoharan6dcc3442012-07-17 17:16:36 +05301036 }
Ben Greear48014162011-01-15 19:13:48 +00001037}
1038
Ben Greear48014162011-01-15 19:13:48 +00001039static int ath9k_add_interface(struct ieee80211_hw *hw,
1040 struct ieee80211_vif *vif)
1041{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001042 struct ath_softc *sc = hw->priv;
Ben Greear48014162011-01-15 19:13:48 +00001043 struct ath_hw *ah = sc->sc_ah;
1044 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkauf89d1bc2013-08-06 14:18:13 +02001045 struct ath_vif *avp = (void *)vif->drv_priv;
1046 struct ath_node *an = &avp->mcast_node;
Ben Greear48014162011-01-15 19:13:48 +00001047
1048 mutex_lock(&sc->mutex);
1049
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001050 if (config_enabled(CONFIG_ATH9K_TX99)) {
1051 if (sc->nvifs >= 1) {
1052 mutex_unlock(&sc->mutex);
1053 return -EOPNOTSUPP;
1054 }
1055 sc->tx99_vif = vif;
1056 }
1057
Joe Perchesd2182b62011-12-15 14:55:53 -08001058 ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
Ben Greear48014162011-01-15 19:13:48 +00001059 sc->nvifs++;
1060
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301061 ath9k_ps_wakeup(sc);
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301062 ath9k_calculate_summary_state(hw, vif);
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301063 ath9k_ps_restore(sc);
1064
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301065 if (ath9k_uses_beacons(vif->type))
1066 ath9k_beacon_assign_slot(sc, vif);
1067
Felix Fietkauf89d1bc2013-08-06 14:18:13 +02001068 an->sc = sc;
1069 an->sta = NULL;
1070 an->vif = vif;
1071 an->no_ps_filter = true;
1072 ath_tx_node_init(sc, an);
1073
Ben Greear48014162011-01-15 19:13:48 +00001074 mutex_unlock(&sc->mutex);
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301075 return 0;
Ben Greear48014162011-01-15 19:13:48 +00001076}
1077
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301078static int ath9k_change_interface(struct ieee80211_hw *hw,
1079 struct ieee80211_vif *vif,
1080 enum nl80211_iftype new_type,
1081 bool p2p)
1082{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001083 struct ath_softc *sc = hw->priv;
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301084 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1085
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301086 mutex_lock(&sc->mutex);
Ben Greear48014162011-01-15 19:13:48 +00001087
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001088 if (config_enabled(CONFIG_ATH9K_TX99)) {
1089 mutex_unlock(&sc->mutex);
1090 return -EOPNOTSUPP;
1091 }
1092
1093 ath_dbg(common, CONFIG, "Change Interface\n");
1094
Ben Greear48014162011-01-15 19:13:48 +00001095 if (ath9k_uses_beacons(vif->type))
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301096 ath9k_beacon_remove_slot(sc, vif);
Ben Greear48014162011-01-15 19:13:48 +00001097
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301098 vif->type = new_type;
1099 vif->p2p = p2p;
1100
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301101 ath9k_ps_wakeup(sc);
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301102 ath9k_calculate_summary_state(hw, vif);
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301103 ath9k_ps_restore(sc);
1104
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301105 if (ath9k_uses_beacons(vif->type))
1106 ath9k_beacon_assign_slot(sc, vif);
1107
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301108 mutex_unlock(&sc->mutex);
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301109 return 0;
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301110}
1111
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001112static void ath9k_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001113 struct ieee80211_vif *vif)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001114{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001115 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001116 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkauf89d1bc2013-08-06 14:18:13 +02001117 struct ath_vif *avp = (void *)vif->drv_priv;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001118
Joe Perchesd2182b62011-12-15 14:55:53 -08001119 ath_dbg(common, CONFIG, "Detach Interface\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001120
Sujith141b38b2009-02-04 08:10:07 +05301121 mutex_lock(&sc->mutex);
1122
Ben Greear48014162011-01-15 19:13:48 +00001123 sc->nvifs--;
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001124 sc->tx99_vif = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001125
Ben Greear48014162011-01-15 19:13:48 +00001126 if (ath9k_uses_beacons(vif->type))
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301127 ath9k_beacon_remove_slot(sc, vif);
Jouni Malinen2c3db3d2009-03-03 19:23:26 +02001128
Simon Wunderlichd074e8d2013-08-14 08:01:38 +02001129 if (sc->csa_vif == vif)
1130 sc->csa_vif = NULL;
1131
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301132 ath9k_ps_wakeup(sc);
Ben Greear48014162011-01-15 19:13:48 +00001133 ath9k_calculate_summary_state(hw, NULL);
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301134 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301135
Felix Fietkauf89d1bc2013-08-06 14:18:13 +02001136 ath_tx_node_cleanup(sc, &avp->mcast_node);
1137
Sujith141b38b2009-02-04 08:10:07 +05301138 mutex_unlock(&sc->mutex);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001139}
1140
Senthil Balasubramanianfbab7392010-10-05 20:36:40 +05301141static void ath9k_enable_ps(struct ath_softc *sc)
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301142{
Pavel Roskin30691682010-03-31 18:05:31 -04001143 struct ath_hw *ah = sc->sc_ah;
Sujith Manoharanad128862012-04-24 10:23:20 +05301144 struct ath_common *common = ath9k_hw_common(ah);
Pavel Roskin30691682010-03-31 18:05:31 -04001145
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001146 if (config_enabled(CONFIG_ATH9K_TX99))
1147 return;
1148
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301149 sc->ps_enabled = true;
Pavel Roskin30691682010-03-31 18:05:31 -04001150 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
1151 if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) {
1152 ah->imask |= ATH9K_INT_TIM_TIMER;
Felix Fietkau72d874c2011-10-08 20:06:19 +02001153 ath9k_hw_set_interrupts(ah);
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301154 }
Vasanthakumar Thiagarajanfdf76622010-05-17 18:57:55 -07001155 ath9k_hw_setrxabort(ah, 1);
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301156 }
Sujith Manoharanad128862012-04-24 10:23:20 +05301157 ath_dbg(common, PS, "PowerSave enabled\n");
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301158}
1159
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301160static void ath9k_disable_ps(struct ath_softc *sc)
1161{
1162 struct ath_hw *ah = sc->sc_ah;
Sujith Manoharanad128862012-04-24 10:23:20 +05301163 struct ath_common *common = ath9k_hw_common(ah);
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301164
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001165 if (config_enabled(CONFIG_ATH9K_TX99))
1166 return;
1167
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301168 sc->ps_enabled = false;
1169 ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
1170 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
1171 ath9k_hw_setrxabort(ah, 0);
1172 sc->ps_flags &= ~(PS_WAIT_FOR_BEACON |
1173 PS_WAIT_FOR_CAB |
1174 PS_WAIT_FOR_PSPOLL_DATA |
1175 PS_WAIT_FOR_TX_ACK);
1176 if (ah->imask & ATH9K_INT_TIM_TIMER) {
1177 ah->imask &= ~ATH9K_INT_TIM_TIMER;
Felix Fietkau72d874c2011-10-08 20:06:19 +02001178 ath9k_hw_set_interrupts(ah);
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301179 }
1180 }
Sujith Manoharanad128862012-04-24 10:23:20 +05301181 ath_dbg(common, PS, "PowerSave disabled\n");
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301182}
1183
Simon Wunderliche93d0832013-01-08 14:48:58 +01001184void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw)
1185{
1186 struct ath_softc *sc = hw->priv;
1187 struct ath_hw *ah = sc->sc_ah;
1188 struct ath_common *common = ath9k_hw_common(ah);
1189 u32 rxfilter;
1190
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001191 if (config_enabled(CONFIG_ATH9K_TX99))
1192 return;
1193
Simon Wunderliche93d0832013-01-08 14:48:58 +01001194 if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
1195 ath_err(common, "spectrum analyzer not implemented on this hardware\n");
1196 return;
1197 }
1198
1199 ath9k_ps_wakeup(sc);
1200 rxfilter = ath9k_hw_getrxfilter(ah);
1201 ath9k_hw_setrxfilter(ah, rxfilter |
1202 ATH9K_RX_FILTER_PHYRADAR |
1203 ATH9K_RX_FILTER_PHYERR);
1204
1205 /* TODO: usually this should not be neccesary, but for some reason
1206 * (or in some mode?) the trigger must be called after the
1207 * configuration, otherwise the register will have its values reset
1208 * (on my ar9220 to value 0x01002310)
1209 */
1210 ath9k_spectral_scan_config(hw, sc->spectral_mode);
1211 ath9k_hw_ops(ah)->spectral_scan_trigger(ah);
1212 ath9k_ps_restore(sc);
1213}
1214
1215int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
1216 enum spectral_mode spectral_mode)
1217{
1218 struct ath_softc *sc = hw->priv;
1219 struct ath_hw *ah = sc->sc_ah;
1220 struct ath_common *common = ath9k_hw_common(ah);
Simon Wunderliche93d0832013-01-08 14:48:58 +01001221
1222 if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
1223 ath_err(common, "spectrum analyzer not implemented on this hardware\n");
1224 return -1;
1225 }
1226
Simon Wunderliche93d0832013-01-08 14:48:58 +01001227 switch (spectral_mode) {
1228 case SPECTRAL_DISABLED:
Simon Wunderlich04ccd4a2013-01-23 17:38:04 +01001229 sc->spec_config.enabled = 0;
Simon Wunderliche93d0832013-01-08 14:48:58 +01001230 break;
1231 case SPECTRAL_BACKGROUND:
1232 /* send endless samples.
1233 * TODO: is this really useful for "background"?
1234 */
Simon Wunderlich04ccd4a2013-01-23 17:38:04 +01001235 sc->spec_config.endless = 1;
1236 sc->spec_config.enabled = 1;
Simon Wunderliche93d0832013-01-08 14:48:58 +01001237 break;
1238 case SPECTRAL_CHANSCAN:
Simon Wunderliche93d0832013-01-08 14:48:58 +01001239 case SPECTRAL_MANUAL:
Simon Wunderlich04ccd4a2013-01-23 17:38:04 +01001240 sc->spec_config.endless = 0;
1241 sc->spec_config.enabled = 1;
Simon Wunderliche93d0832013-01-08 14:48:58 +01001242 break;
1243 default:
1244 return -1;
1245 }
1246
1247 ath9k_ps_wakeup(sc);
Simon Wunderlich04ccd4a2013-01-23 17:38:04 +01001248 ath9k_hw_ops(ah)->spectral_scan_config(ah, &sc->spec_config);
Simon Wunderliche93d0832013-01-08 14:48:58 +01001249 ath9k_ps_restore(sc);
1250
1251 sc->spectral_mode = spectral_mode;
1252
1253 return 0;
1254}
1255
Johannes Berge8975582008-10-09 12:18:51 +02001256static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001257{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001258 struct ath_softc *sc = hw->priv;
Felix Fietkau34300982010-10-10 18:21:52 +02001259 struct ath_hw *ah = sc->sc_ah;
1260 struct ath_common *common = ath9k_hw_common(ah);
Johannes Berge8975582008-10-09 12:18:51 +02001261 struct ieee80211_conf *conf = &hw->conf;
Felix Fietkau75600ab2012-04-12 20:36:31 +02001262 bool reset_channel = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001263
Felix Fietkauc0c11742011-11-16 13:08:41 +01001264 ath9k_ps_wakeup(sc);
Sujithaa33de02008-12-18 11:40:16 +05301265 mutex_lock(&sc->mutex);
Sujith141b38b2009-02-04 08:10:07 +05301266
Felix Fietkaudaa1b6e2011-11-16 13:08:43 +01001267 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Felix Fietkau7545daf2011-01-24 19:23:16 +01001268 sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
Rajkumar Manoharanb73f3e72012-07-01 19:53:53 +05301269 if (sc->ps_idle) {
Felix Fietkaudaa1b6e2011-11-16 13:08:43 +01001270 ath_cancel_work(sc);
Rajkumar Manoharanb73f3e72012-07-01 19:53:53 +05301271 ath9k_stop_btcoex(sc);
1272 } else {
1273 ath9k_start_btcoex(sc);
Felix Fietkau75600ab2012-04-12 20:36:31 +02001274 /*
1275 * The chip needs a reset to properly wake up from
1276 * full sleep
1277 */
1278 reset_channel = ah->chip_fullsleep;
Rajkumar Manoharanb73f3e72012-07-01 19:53:53 +05301279 }
Felix Fietkaudaa1b6e2011-11-16 13:08:43 +01001280 }
Luis R. Rodriguez64839172009-07-14 20:22:53 -04001281
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001282 /*
1283 * We just prepare to enable PS. We have to wait until our AP has
1284 * ACK'd our null data frame to disable RX otherwise we'll ignore
1285 * those ACKs and end up retransmitting the same null data frames.
1286 * IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode.
1287 */
Vivek Natarajan3cbb5dd2009-01-20 11:17:08 +05301288 if (changed & IEEE80211_CONF_CHANGE_PS) {
Luis R. Rodriguez8ab2cd02010-09-16 15:12:26 -04001289 unsigned long flags;
1290 spin_lock_irqsave(&sc->sc_pm_lock, flags);
Senthil Balasubramanianfbab7392010-10-05 20:36:40 +05301291 if (conf->flags & IEEE80211_CONF_PS)
1292 ath9k_enable_ps(sc);
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301293 else
1294 ath9k_disable_ps(sc);
Luis R. Rodriguez8ab2cd02010-09-16 15:12:26 -04001295 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
Vivek Natarajan3cbb5dd2009-01-20 11:17:08 +05301296 }
1297
Sujith199afd92010-01-08 10:36:13 +05301298 if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
1299 if (conf->flags & IEEE80211_CONF_MONITOR) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001300 ath_dbg(common, CONFIG, "Monitor mode is enabled\n");
Rajkumar Manoharan5f841b42010-10-27 18:31:15 +05301301 sc->sc_ah->is_monitoring = true;
1302 } else {
Joe Perchesd2182b62011-12-15 14:55:53 -08001303 ath_dbg(common, CONFIG, "Monitor mode is disabled\n");
Rajkumar Manoharan5f841b42010-10-27 18:31:15 +05301304 sc->sc_ah->is_monitoring = false;
Sujith199afd92010-01-08 10:36:13 +05301305 }
1306 }
1307
Felix Fietkau75600ab2012-04-12 20:36:31 +02001308 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) {
Felix Fietkau45c67f62013-10-11 23:30:58 +02001309 if (ath_set_channel(sc, &hw->conf.chandef) < 0) {
Joe Perches38002762010-12-02 19:12:36 -08001310 ath_err(common, "Unable to set channel\n");
Sujithaa33de02008-12-18 11:40:16 +05301311 mutex_unlock(&sc->mutex);
Rajkumar Manoharan8389fb32012-06-11 12:19:30 +05301312 ath9k_ps_restore(sc);
Sujithe11602b2008-11-27 09:46:27 +05301313 return -EINVAL;
1314 }
Sujith094d05d2008-12-12 11:57:43 +05301315 }
Sujith86b89ee2008-08-07 10:54:57 +05301316
Luis R. Rodriguezc9f6a652010-01-19 14:04:19 -05001317 if (changed & IEEE80211_CONF_CHANGE_POWER) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001318 ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level);
Sujith17d79042009-02-09 13:27:03 +05301319 sc->config.txpowlimit = 2 * conf->power_level;
Rajkumar Manoharan5048e8c2011-01-31 23:47:44 +05301320 ath9k_cmn_update_txpow(ah, sc->curtxpow,
1321 sc->config.txpowlimit, &sc->curtxpow);
Luis R. Rodriguez64839172009-07-14 20:22:53 -04001322 }
1323
Sujithaa33de02008-12-18 11:40:16 +05301324 mutex_unlock(&sc->mutex);
Felix Fietkauc0c11742011-11-16 13:08:41 +01001325 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301326
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001327 return 0;
1328}
1329
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001330#define SUPPORTED_FILTERS \
1331 (FIF_PROMISC_IN_BSS | \
1332 FIF_ALLMULTI | \
1333 FIF_CONTROL | \
Luis R. Rodriguezaf6a3fc2009-08-08 21:55:16 -04001334 FIF_PSPOLL | \
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001335 FIF_OTHER_BSS | \
1336 FIF_BCN_PRBRESP_PROMISC | \
Jouni Malinen9c1d8e42010-10-13 17:29:31 +03001337 FIF_PROBE_REQ | \
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001338 FIF_FCSFAIL)
1339
Sujith7dcfdcd2008-08-11 14:03:13 +05301340/* FIXME: sc->sc_full_reset ? */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001341static void ath9k_configure_filter(struct ieee80211_hw *hw,
1342 unsigned int changed_flags,
1343 unsigned int *total_flags,
Johannes Berg3ac64be2009-08-17 16:16:53 +02001344 u64 multicast)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001345{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001346 struct ath_softc *sc = hw->priv;
Sujith7dcfdcd2008-08-11 14:03:13 +05301347 u32 rfilt;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001348
1349 changed_flags &= SUPPORTED_FILTERS;
1350 *total_flags &= SUPPORTED_FILTERS;
1351
Sujithb77f4832008-12-07 21:44:03 +05301352 sc->rx.rxfilter = *total_flags;
Jouni Malinenaa68aea2009-05-19 17:01:41 +03001353 ath9k_ps_wakeup(sc);
Sujith7dcfdcd2008-08-11 14:03:13 +05301354 rfilt = ath_calcrxfilter(sc);
1355 ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
Jouni Malinenaa68aea2009-05-19 17:01:41 +03001356 ath9k_ps_restore(sc);
Sujith7dcfdcd2008-08-11 14:03:13 +05301357
Joe Perchesd2182b62011-12-15 14:55:53 -08001358 ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG, "Set HW RX filter: 0x%x\n",
1359 rfilt);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001360}
1361
Johannes Berg4ca77862010-02-19 19:06:56 +01001362static int ath9k_sta_add(struct ieee80211_hw *hw,
1363 struct ieee80211_vif *vif,
1364 struct ieee80211_sta *sta)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001365{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001366 struct ath_softc *sc = hw->priv;
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001367 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1368 struct ath_node *an = (struct ath_node *) sta->drv_priv;
1369 struct ieee80211_key_conf ps_key = { };
Felix Fietkau4ef69d02013-04-27 11:47:01 +02001370 int key;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001371
Ben Greear7e1e3862011-11-03 11:33:13 -07001372 ath_node_attach(sc, sta, vif);
Felix Fietkauf59a59f2011-05-10 20:52:22 +02001373
1374 if (vif->type != NL80211_IFTYPE_AP &&
1375 vif->type != NL80211_IFTYPE_AP_VLAN)
1376 return 0;
1377
Felix Fietkau4ef69d02013-04-27 11:47:01 +02001378 key = ath_key_config(common, vif, sta, &ps_key);
1379 if (key > 0)
1380 an->ps_key = key;
Johannes Berg4ca77862010-02-19 19:06:56 +01001381
1382 return 0;
1383}
1384
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001385static void ath9k_del_ps_key(struct ath_softc *sc,
1386 struct ieee80211_vif *vif,
1387 struct ieee80211_sta *sta)
1388{
1389 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1390 struct ath_node *an = (struct ath_node *) sta->drv_priv;
1391 struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key };
1392
1393 if (!an->ps_key)
1394 return;
1395
1396 ath_key_delete(common, &ps_key);
Felix Fietkau4ef69d02013-04-27 11:47:01 +02001397 an->ps_key = 0;
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001398}
1399
Johannes Berg4ca77862010-02-19 19:06:56 +01001400static int ath9k_sta_remove(struct ieee80211_hw *hw,
1401 struct ieee80211_vif *vif,
1402 struct ieee80211_sta *sta)
1403{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001404 struct ath_softc *sc = hw->priv;
Johannes Berg4ca77862010-02-19 19:06:56 +01001405
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001406 ath9k_del_ps_key(sc, vif, sta);
Johannes Berg4ca77862010-02-19 19:06:56 +01001407 ath_node_detach(sc, sta);
1408
1409 return 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001410}
1411
Felix Fietkau55195412011-04-17 23:28:09 +02001412static void ath9k_sta_notify(struct ieee80211_hw *hw,
1413 struct ieee80211_vif *vif,
1414 enum sta_notify_cmd cmd,
1415 struct ieee80211_sta *sta)
1416{
1417 struct ath_softc *sc = hw->priv;
1418 struct ath_node *an = (struct ath_node *) sta->drv_priv;
1419
1420 switch (cmd) {
1421 case STA_NOTIFY_SLEEP:
1422 an->sleeping = true;
Johannes Berg042ec452011-09-29 16:04:26 +02001423 ath_tx_aggr_sleep(sta, sc, an);
Felix Fietkau55195412011-04-17 23:28:09 +02001424 break;
1425 case STA_NOTIFY_AWAKE:
1426 an->sleeping = false;
1427 ath_tx_aggr_wakeup(sc, an);
1428 break;
1429 }
1430}
1431
Eliad Peller8a3a3c82011-10-02 10:15:52 +02001432static int ath9k_conf_tx(struct ieee80211_hw *hw,
1433 struct ieee80211_vif *vif, u16 queue,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001434 const struct ieee80211_tx_queue_params *params)
1435{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001436 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001437 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau066dae92010-11-07 14:59:39 +01001438 struct ath_txq *txq;
Sujithea9880f2008-08-07 10:53:10 +05301439 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +01001440 int ret = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001441
Sujith Manoharanbea843c2012-11-21 18:13:10 +05301442 if (queue >= IEEE80211_NUM_ACS)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001443 return 0;
1444
Felix Fietkau066dae92010-11-07 14:59:39 +01001445 txq = sc->tx.txq_map[queue];
1446
Felix Fietkau96f372c2011-04-07 19:07:17 +02001447 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301448 mutex_lock(&sc->mutex);
1449
Sujith1ffb0612009-03-30 15:28:46 +05301450 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
1451
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001452 qi.tqi_aifs = params->aifs;
1453 qi.tqi_cwmin = params->cw_min;
1454 qi.tqi_cwmax = params->cw_max;
Felix Fietkau531bd072012-07-15 19:53:34 +02001455 qi.tqi_burstTime = params->txop * 32;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001456
Joe Perchesd2182b62011-12-15 14:55:53 -08001457 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -08001458 "Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
1459 queue, txq->axq_qnum, params->aifs, params->cw_min,
1460 params->cw_max, params->txop);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001461
Felix Fietkauaa5955c2012-07-15 19:53:36 +02001462 ath_update_max_aggr_framelen(sc, queue, qi.tqi_burstTime);
Felix Fietkau066dae92010-11-07 14:59:39 +01001463 ret = ath_txq_update(sc, txq->axq_qnum, &qi);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001464 if (ret)
Joe Perches38002762010-12-02 19:12:36 -08001465 ath_err(common, "TXQ Update failed\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001466
Sujith141b38b2009-02-04 08:10:07 +05301467 mutex_unlock(&sc->mutex);
Felix Fietkau96f372c2011-04-07 19:07:17 +02001468 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301469
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001470 return ret;
1471}
1472
1473static int ath9k_set_key(struct ieee80211_hw *hw,
1474 enum set_key_cmd cmd,
Johannes Bergdc822b52008-12-29 12:55:09 +01001475 struct ieee80211_vif *vif,
1476 struct ieee80211_sta *sta,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001477 struct ieee80211_key_conf *key)
1478{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001479 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001480 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001481 int ret = 0;
1482
John W. Linville3e6109c2011-01-05 09:39:17 -05001483 if (ath9k_modparam_nohwcrypt)
Jouni Malinenb3bd89c2009-02-24 13:42:01 +02001484 return -ENOSPC;
1485
Chun-Yeow Yeoh5bd5e9a2011-12-07 12:45:46 -08001486 if ((vif->type == NL80211_IFTYPE_ADHOC ||
1487 vif->type == NL80211_IFTYPE_MESH_POINT) &&
Jouni Malinencfdc9a82011-03-23 14:52:19 +02001488 (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
1489 key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
1490 !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
1491 /*
1492 * For now, disable hw crypto for the RSN IBSS group keys. This
1493 * could be optimized in the future to use a modified key cache
1494 * design to support per-STA RX GTK, but until that gets
1495 * implemented, use of software crypto for group addressed
1496 * frames is a acceptable to allow RSN IBSS to be used.
1497 */
1498 return -EOPNOTSUPP;
1499 }
1500
Sujith141b38b2009-02-04 08:10:07 +05301501 mutex_lock(&sc->mutex);
Vivek Natarajan3cbb5dd2009-01-20 11:17:08 +05301502 ath9k_ps_wakeup(sc);
Joe Perchesd2182b62011-12-15 14:55:53 -08001503 ath_dbg(common, CONFIG, "Set HW Key\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001504
1505 switch (cmd) {
1506 case SET_KEY:
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001507 if (sta)
1508 ath9k_del_ps_key(sc, vif, sta);
1509
Bruno Randolf040e5392010-09-08 16:05:04 +09001510 ret = ath_key_config(common, vif, sta, key);
Jouni Malinen6ace2892008-12-17 13:32:17 +02001511 if (ret >= 0) {
1512 key->hw_key_idx = ret;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001513 /* push IV and Michael MIC generation to stack */
1514 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Johannes Berg97359d12010-08-10 09:46:38 +02001515 if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
Senthil Balasubramanian1b961752008-09-01 19:45:21 +05301516 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
Johannes Berg97359d12010-08-10 09:46:38 +02001517 if (sc->sc_ah->sw_mgmt_crypto &&
1518 key->cipher == WLAN_CIPHER_SUITE_CCMP)
Johannes Berge548c492012-09-04 17:08:23 +02001519 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
Jouni Malinen6ace2892008-12-17 13:32:17 +02001520 ret = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001521 }
1522 break;
1523 case DISABLE_KEY:
Bruno Randolf040e5392010-09-08 16:05:04 +09001524 ath_key_delete(common, key);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001525 break;
1526 default:
1527 ret = -EINVAL;
1528 }
1529
Vivek Natarajan3cbb5dd2009-01-20 11:17:08 +05301530 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301531 mutex_unlock(&sc->mutex);
1532
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001533 return ret;
1534}
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301535
1536static void ath9k_set_assoc_state(struct ath_softc *sc,
1537 struct ieee80211_vif *vif)
Rajkumar Manoharan4f5ef75b2011-04-04 22:56:18 +05301538{
Rajkumar Manoharan4f5ef75b2011-04-04 22:56:18 +05301539 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Rajkumar Manoharan4f5ef75b2011-04-04 22:56:18 +05301540 struct ath_vif *avp = (void *)vif->drv_priv;
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301541 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Sujith Manoharan07c15a32012-06-04 20:24:07 +05301542 unsigned long flags;
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301543
1544 set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
1545 avp->primary_sta_vif = true;
1546
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301547 /*
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301548 * Set the AID, BSSID and do beacon-sync only when
1549 * the HW opmode is STATION.
1550 *
1551 * But the primary bit is set above in any case.
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301552 */
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301553 if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
1554 return;
1555
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301556 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1557 common->curaid = bss_conf->aid;
1558 ath9k_hw_write_associd(sc->sc_ah);
Rajkumar Manoharan4f5ef75b2011-04-04 22:56:18 +05301559
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301560 sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
1561 sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
Rajkumar Manoharan4f5ef75b2011-04-04 22:56:18 +05301562
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301563 spin_lock_irqsave(&sc->sc_pm_lock, flags);
1564 sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
1565 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
1566
Rajkumar Manoharan50072eb2012-10-12 14:07:22 +05301567 if (ath9k_hw_mci_is_enabled(sc->sc_ah))
1568 ath9k_mci_update_wlan_channels(sc, false);
1569
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301570 ath_dbg(common, CONFIG,
1571 "Primary Station interface: %pM, BSSID: %pM\n",
1572 vif->addr, common->curbssid);
1573}
1574
1575static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
1576{
1577 struct ath_softc *sc = data;
1578 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
1579
1580 if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
1581 return;
1582
1583 if (bss_conf->assoc)
1584 ath9k_set_assoc_state(sc, vif);
Rajkumar Manoharan4f5ef75b2011-04-04 22:56:18 +05301585}
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001586
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001587static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
1588 struct ieee80211_vif *vif,
1589 struct ieee80211_bss_conf *bss_conf,
1590 u32 changed)
1591{
Sujith Manoharanda0d45f2012-07-17 17:16:29 +05301592#define CHECK_ANI \
1593 (BSS_CHANGED_ASSOC | \
1594 BSS_CHANGED_IBSS | \
1595 BSS_CHANGED_BEACON_ENABLED)
1596
Felix Fietkau9ac586152011-01-24 19:23:18 +01001597 struct ath_softc *sc = hw->priv;
Johannes Berg2d0ddec2009-04-23 16:13:26 +02001598 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguez15107182009-09-10 09:22:37 -07001599 struct ath_common *common = ath9k_hw_common(ah);
Johannes Berg2d0ddec2009-04-23 16:13:26 +02001600 struct ath_vif *avp = (void *)vif->drv_priv;
Felix Fietkau0005baf2010-01-15 02:33:40 +01001601 int slottime;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001602
Felix Fietkau96f372c2011-04-07 19:07:17 +02001603 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301604 mutex_lock(&sc->mutex);
1605
Rajkumar Manoharan9f619032012-03-10 05:06:49 +05301606 if (changed & BSS_CHANGED_ASSOC) {
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301607 ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n",
1608 bss_conf->bssid, bss_conf->assoc);
Sujithc6089cc2009-11-16 11:40:48 +05301609
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301610 if (avp->primary_sta_vif && !bss_conf->assoc) {
1611 clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
1612 avp->primary_sta_vif = false;
1613
1614 if (ah->opmode == NL80211_IFTYPE_STATION)
1615 clear_bit(SC_OP_BEACONS, &sc->sc_flags);
1616 }
1617
Johannes Berg8b2c9822012-11-06 20:23:30 +01001618 ieee80211_iterate_active_interfaces_atomic(
1619 sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
1620 ath9k_bss_assoc_iter, sc);
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301621
1622 if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) &&
1623 ah->opmode == NL80211_IFTYPE_STATION) {
1624 memset(common->curbssid, 0, ETH_ALEN);
1625 common->curaid = 0;
1626 ath9k_hw_write_associd(sc->sc_ah);
Rajkumar Manoharan50072eb2012-10-12 14:07:22 +05301627 if (ath9k_hw_mci_is_enabled(sc->sc_ah))
1628 ath9k_mci_update_wlan_channels(sc, true);
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301629 }
Johannes Berg2d0ddec2009-04-23 16:13:26 +02001630 }
1631
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301632 if (changed & BSS_CHANGED_IBSS) {
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301633 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1634 common->curaid = bss_conf->aid;
1635 ath9k_hw_write_associd(sc->sc_ah);
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301636 }
1637
Sujith Manoharanef4ad632012-07-17 17:15:56 +05301638 if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
1639 (changed & BSS_CHANGED_BEACON_INT)) {
Sujith Manoharan2f8e82e2012-07-17 17:16:16 +05301640 if (ah->opmode == NL80211_IFTYPE_AP &&
1641 bss_conf->enable_beacon)
1642 ath9k_set_tsfadjust(sc, vif);
Sujith Manoharanef4ad632012-07-17 17:15:56 +05301643 if (ath9k_allow_beacon_config(sc, vif))
1644 ath9k_beacon_config(sc, vif, changed);
Johannes Berg2d0ddec2009-04-23 16:13:26 +02001645 }
1646
Felix Fietkau0005baf2010-01-15 02:33:40 +01001647 if (changed & BSS_CHANGED_ERP_SLOT) {
1648 if (bss_conf->use_short_slot)
1649 slottime = 9;
1650 else
1651 slottime = 20;
1652 if (vif->type == NL80211_IFTYPE_AP) {
1653 /*
1654 * Defer update, so that connected stations can adjust
1655 * their settings at the same time.
1656 * See beacon.c for more details
1657 */
1658 sc->beacon.slottime = slottime;
1659 sc->beacon.updateslot = UPDATE;
1660 } else {
1661 ah->slottime = slottime;
1662 ath9k_hw_init_global_settings(ah);
1663 }
1664 }
1665
Sujith Manoharanda0d45f2012-07-17 17:16:29 +05301666 if (changed & CHECK_ANI)
1667 ath_check_ani(sc);
1668
Sujith141b38b2009-02-04 08:10:07 +05301669 mutex_unlock(&sc->mutex);
Felix Fietkau96f372c2011-04-07 19:07:17 +02001670 ath9k_ps_restore(sc);
Sujith Manoharanda0d45f2012-07-17 17:16:29 +05301671
1672#undef CHECK_ANI
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001673}
1674
Eliad Peller37a41b42011-09-21 14:06:11 +03001675static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001676{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001677 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001678 u64 tsf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001679
Sujith141b38b2009-02-04 08:10:07 +05301680 mutex_lock(&sc->mutex);
Sujith Manoharan9abbfb22010-12-10 11:27:06 +05301681 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301682 tsf = ath9k_hw_gettsf64(sc->sc_ah);
Sujith Manoharan9abbfb22010-12-10 11:27:06 +05301683 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301684 mutex_unlock(&sc->mutex);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001685
1686 return tsf;
1687}
1688
Eliad Peller37a41b42011-09-21 14:06:11 +03001689static void ath9k_set_tsf(struct ieee80211_hw *hw,
1690 struct ieee80211_vif *vif,
1691 u64 tsf)
Alina Friedrichsen3b5d6652009-01-24 07:09:59 +01001692{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001693 struct ath_softc *sc = hw->priv;
Alina Friedrichsen3b5d6652009-01-24 07:09:59 +01001694
Sujith141b38b2009-02-04 08:10:07 +05301695 mutex_lock(&sc->mutex);
Sujith Manoharan9abbfb22010-12-10 11:27:06 +05301696 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301697 ath9k_hw_settsf64(sc->sc_ah, tsf);
Sujith Manoharan9abbfb22010-12-10 11:27:06 +05301698 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301699 mutex_unlock(&sc->mutex);
Alina Friedrichsen3b5d6652009-01-24 07:09:59 +01001700}
1701
Eliad Peller37a41b42011-09-21 14:06:11 +03001702static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001703{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001704 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001705
Sujith141b38b2009-02-04 08:10:07 +05301706 mutex_lock(&sc->mutex);
Luis R. Rodriguez21526d52009-09-09 20:05:39 -07001707
1708 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301709 ath9k_hw_reset_tsf(sc->sc_ah);
Luis R. Rodriguez21526d52009-09-09 20:05:39 -07001710 ath9k_ps_restore(sc);
1711
Sujith141b38b2009-02-04 08:10:07 +05301712 mutex_unlock(&sc->mutex);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001713}
1714
1715static int ath9k_ampdu_action(struct ieee80211_hw *hw,
Johannes Bergc951ad32009-11-16 12:00:38 +01001716 struct ieee80211_vif *vif,
Sujith141b38b2009-02-04 08:10:07 +05301717 enum ieee80211_ampdu_mlme_action action,
1718 struct ieee80211_sta *sta,
Johannes Berg0b01f032011-01-18 13:51:05 +01001719 u16 tid, u16 *ssn, u8 buf_size)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001720{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001721 struct ath_softc *sc = hw->priv;
Felix Fietkau16e23422013-05-17 12:58:24 +02001722 bool flush = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001723 int ret = 0;
1724
Sujith Manoharan7ca7c772013-05-08 05:03:32 +05301725 mutex_lock(&sc->mutex);
Johannes Berg85ad1812010-06-10 10:21:49 +02001726
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001727 switch (action) {
1728 case IEEE80211_AMPDU_RX_START:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001729 break;
1730 case IEEE80211_AMPDU_RX_STOP:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001731 break;
1732 case IEEE80211_AMPDU_TX_START:
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001733 ath9k_ps_wakeup(sc);
Felix Fietkau231c3a12010-09-20 19:35:28 +02001734 ret = ath_tx_aggr_start(sc, sta, tid, ssn);
1735 if (!ret)
1736 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001737 ath9k_ps_restore(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001738 break;
Johannes Berg18b559d2012-07-18 13:51:25 +02001739 case IEEE80211_AMPDU_TX_STOP_FLUSH:
1740 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
Felix Fietkau16e23422013-05-17 12:58:24 +02001741 flush = true;
1742 case IEEE80211_AMPDU_TX_STOP_CONT:
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001743 ath9k_ps_wakeup(sc);
Sujithf83da962009-07-23 15:32:37 +05301744 ath_tx_aggr_stop(sc, sta, tid);
Felix Fietkau08c96ab2013-05-18 21:28:15 +02001745 if (!flush)
Felix Fietkau16e23422013-05-17 12:58:24 +02001746 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001747 ath9k_ps_restore(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001748 break;
Johannes Bergb1720232009-03-23 17:28:39 +01001749 case IEEE80211_AMPDU_TX_OPERATIONAL:
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001750 ath9k_ps_wakeup(sc);
Sujith8469cde2008-10-29 10:19:28 +05301751 ath_tx_aggr_resume(sc, sta, tid);
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001752 ath9k_ps_restore(sc);
Sujith8469cde2008-10-29 10:19:28 +05301753 break;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001754 default:
Joe Perches38002762010-12-02 19:12:36 -08001755 ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001756 }
1757
Sujith Manoharan7ca7c772013-05-08 05:03:32 +05301758 mutex_unlock(&sc->mutex);
Johannes Berg85ad1812010-06-10 10:21:49 +02001759
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001760 return ret;
1761}
1762
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001763static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
1764 struct survey_info *survey)
1765{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001766 struct ath_softc *sc = hw->priv;
Felix Fietkau34300982010-10-10 18:21:52 +02001767 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau39162db2010-09-29 19:12:06 +02001768 struct ieee80211_supported_band *sband;
Felix Fietkau34300982010-10-10 18:21:52 +02001769 struct ieee80211_channel *chan;
1770 unsigned long flags;
1771 int pos;
1772
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001773 if (config_enabled(CONFIG_ATH9K_TX99))
1774 return -EOPNOTSUPP;
1775
Felix Fietkau34300982010-10-10 18:21:52 +02001776 spin_lock_irqsave(&common->cc_lock, flags);
1777 if (idx == 0)
1778 ath_update_survey_stats(sc);
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001779
Felix Fietkau39162db2010-09-29 19:12:06 +02001780 sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ];
1781 if (sband && idx >= sband->n_channels) {
1782 idx -= sband->n_channels;
1783 sband = NULL;
1784 }
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001785
Felix Fietkau39162db2010-09-29 19:12:06 +02001786 if (!sband)
1787 sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ];
1788
Felix Fietkau34300982010-10-10 18:21:52 +02001789 if (!sband || idx >= sband->n_channels) {
1790 spin_unlock_irqrestore(&common->cc_lock, flags);
1791 return -ENOENT;
Felix Fietkau4f1a5a42010-09-29 17:15:28 +02001792 }
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001793
Felix Fietkau34300982010-10-10 18:21:52 +02001794 chan = &sband->channels[idx];
1795 pos = chan->hw_value;
1796 memcpy(survey, &sc->survey[pos], sizeof(*survey));
1797 survey->channel = chan;
1798 spin_unlock_irqrestore(&common->cc_lock, flags);
1799
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001800 return 0;
1801}
1802
Felix Fietkaue239d852010-01-15 02:34:58 +01001803static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
1804{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001805 struct ath_softc *sc = hw->priv;
Felix Fietkaue239d852010-01-15 02:34:58 +01001806 struct ath_hw *ah = sc->sc_ah;
1807
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001808 if (config_enabled(CONFIG_ATH9K_TX99))
1809 return;
1810
Felix Fietkaue239d852010-01-15 02:34:58 +01001811 mutex_lock(&sc->mutex);
1812 ah->coverage_class = coverage_class;
Mohammed Shafi Shajakhan8b2a38272011-08-24 21:38:07 +05301813
1814 ath9k_ps_wakeup(sc);
Felix Fietkaue239d852010-01-15 02:34:58 +01001815 ath9k_hw_init_global_settings(ah);
Mohammed Shafi Shajakhan8b2a38272011-08-24 21:38:07 +05301816 ath9k_ps_restore(sc);
1817
Felix Fietkaue239d852010-01-15 02:34:58 +01001818 mutex_unlock(&sc->mutex);
1819}
1820
Johannes Berg39ecc012013-02-13 12:11:00 +01001821static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001822{
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001823 struct ath_softc *sc = hw->priv;
Mohammed Shafi Shajakhan99aa55b2011-05-06 20:43:11 +05301824 struct ath_hw *ah = sc->sc_ah;
1825 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkau86271e42011-03-11 21:38:19 +01001826 int timeout = 200; /* ms */
1827 int i, j;
Rajkumar Manoharan2f6fc352011-04-28 15:31:57 +05301828 bool drain_txq;
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001829
1830 mutex_lock(&sc->mutex);
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001831 cancel_delayed_work_sync(&sc->tx_complete_work);
1832
Mohammed Shafi Shajakhan6a6b3f32011-09-09 10:41:08 +05301833 if (ah->ah_flags & AH_UNPLUGGED) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001834 ath_dbg(common, ANY, "Device has been unplugged!\n");
Mohammed Shafi Shajakhan6a6b3f32011-09-09 10:41:08 +05301835 mutex_unlock(&sc->mutex);
1836 return;
1837 }
1838
Sujith Manoharan781b14a2012-06-04 20:23:55 +05301839 if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001840 ath_dbg(common, ANY, "Device not present\n");
Mohammed Shafi Shajakhan99aa55b2011-05-06 20:43:11 +05301841 mutex_unlock(&sc->mutex);
1842 return;
1843 }
1844
Felix Fietkau86271e42011-03-11 21:38:19 +01001845 for (j = 0; j < timeout; j++) {
Mohammed Shafi Shajakhan108697c2011-05-13 20:59:42 +05301846 bool npend = false;
Felix Fietkau86271e42011-03-11 21:38:19 +01001847
1848 if (j)
1849 usleep_range(1000, 2000);
1850
1851 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1852 if (!ATH_TXQ_SETUP(sc, i))
1853 continue;
1854
Mohammed Shafi Shajakhan108697c2011-05-13 20:59:42 +05301855 npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
1856
1857 if (npend)
1858 break;
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001859 }
1860
Felix Fietkau86271e42011-03-11 21:38:19 +01001861 if (!npend)
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01001862 break;
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001863 }
1864
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01001865 if (drop) {
1866 ath9k_ps_wakeup(sc);
1867 spin_lock_bh(&sc->sc_pcu_lock);
Felix Fietkau13815592013-01-20 18:51:53 +01001868 drain_txq = ath_drain_all_txq(sc);
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01001869 spin_unlock_bh(&sc->sc_pcu_lock);
Felix Fietkau9adcf442011-09-03 01:40:26 +02001870
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01001871 if (!drain_txq)
Felix Fietkau13815592013-01-20 18:51:53 +01001872 ath_reset(sc);
Felix Fietkau9adcf442011-09-03 01:40:26 +02001873
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01001874 ath9k_ps_restore(sc);
1875 ieee80211_wake_queues(hw);
1876 }
Senthil Balasubramaniand78f4b32011-03-23 23:07:22 +05301877
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001878 ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
1879 mutex_unlock(&sc->mutex);
1880}
1881
Vivek Natarajan15b91e82011-04-06 11:41:11 +05301882static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
1883{
1884 struct ath_softc *sc = hw->priv;
1885 int i;
1886
1887 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1888 if (!ATH_TXQ_SETUP(sc, i))
1889 continue;
1890
1891 if (ath9k_has_pending_frames(sc, &sc->tx.txq[i]))
1892 return true;
1893 }
1894 return false;
1895}
1896
Mohammed Shafi Shajakhan5595f112011-05-19 18:08:57 +05301897static int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
Felix Fietkauba4903f2011-05-17 21:09:54 +02001898{
1899 struct ath_softc *sc = hw->priv;
1900 struct ath_hw *ah = sc->sc_ah;
1901 struct ieee80211_vif *vif;
1902 struct ath_vif *avp;
1903 struct ath_buf *bf;
1904 struct ath_tx_status ts;
Felix Fietkau4286df62012-02-27 19:58:40 +01001905 bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
Felix Fietkauba4903f2011-05-17 21:09:54 +02001906 int status;
1907
1908 vif = sc->beacon.bslot[0];
1909 if (!vif)
1910 return 0;
1911
Sujith Manoharanaa45fe92012-07-17 17:16:03 +05301912 if (!vif->bss_conf.enable_beacon)
Felix Fietkauba4903f2011-05-17 21:09:54 +02001913 return 0;
1914
Sujith Manoharanaa45fe92012-07-17 17:16:03 +05301915 avp = (void *)vif->drv_priv;
1916
Felix Fietkau4286df62012-02-27 19:58:40 +01001917 if (!sc->beacon.tx_processed && !edma) {
Felix Fietkauba4903f2011-05-17 21:09:54 +02001918 tasklet_disable(&sc->bcon_tasklet);
1919
1920 bf = avp->av_bcbuf;
1921 if (!bf || !bf->bf_mpdu)
1922 goto skip;
1923
1924 status = ath9k_hw_txprocdesc(ah, bf->bf_desc, &ts);
1925 if (status == -EINPROGRESS)
1926 goto skip;
1927
1928 sc->beacon.tx_processed = true;
1929 sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
1930
1931skip:
1932 tasklet_enable(&sc->bcon_tasklet);
1933 }
1934
1935 return sc->beacon.tx_last;
1936}
1937
Mohammed Shafi Shajakhan52c94f42011-08-20 17:21:42 +05301938static int ath9k_get_stats(struct ieee80211_hw *hw,
1939 struct ieee80211_low_level_stats *stats)
1940{
1941 struct ath_softc *sc = hw->priv;
1942 struct ath_hw *ah = sc->sc_ah;
1943 struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats;
1944
1945 stats->dot11ACKFailureCount = mib_stats->ackrcv_bad;
1946 stats->dot11RTSFailureCount = mib_stats->rts_bad;
1947 stats->dot11FCSErrorCount = mib_stats->fcs_bad;
1948 stats->dot11RTSSuccessCount = mib_stats->rts_good;
1949 return 0;
1950}
1951
Felix Fietkau43c35282011-09-03 01:40:27 +02001952static u32 fill_chainmask(u32 cap, u32 new)
1953{
1954 u32 filled = 0;
1955 int i;
1956
1957 for (i = 0; cap && new; i++, cap >>= 1) {
1958 if (!(cap & BIT(0)))
1959 continue;
1960
1961 if (new & BIT(0))
1962 filled |= BIT(i);
1963
1964 new >>= 1;
1965 }
1966
1967 return filled;
1968}
1969
Felix Fietkau5d9c7e32012-07-15 19:53:30 +02001970static bool validate_antenna_mask(struct ath_hw *ah, u32 val)
1971{
Felix Fietkaufea92cb2013-01-20 21:55:22 +01001972 if (AR_SREV_9300_20_OR_LATER(ah))
1973 return true;
1974
Felix Fietkau5d9c7e32012-07-15 19:53:30 +02001975 switch (val & 0x7) {
1976 case 0x1:
1977 case 0x3:
1978 case 0x7:
1979 return true;
1980 case 0x2:
1981 return (ah->caps.rx_chainmask == 1);
1982 default:
1983 return false;
1984 }
1985}
1986
Felix Fietkau43c35282011-09-03 01:40:27 +02001987static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
1988{
1989 struct ath_softc *sc = hw->priv;
1990 struct ath_hw *ah = sc->sc_ah;
1991
Felix Fietkau5d9c7e32012-07-15 19:53:30 +02001992 if (ah->caps.rx_chainmask != 1)
1993 rx_ant |= tx_ant;
1994
1995 if (!validate_antenna_mask(ah, rx_ant) || !tx_ant)
Felix Fietkau43c35282011-09-03 01:40:27 +02001996 return -EINVAL;
1997
1998 sc->ant_rx = rx_ant;
1999 sc->ant_tx = tx_ant;
2000
2001 if (ah->caps.rx_chainmask == 1)
2002 return 0;
2003
2004 /* AR9100 runs into calibration issues if not all rx chains are enabled */
2005 if (AR_SREV_9100(ah))
2006 ah->rxchainmask = 0x7;
2007 else
2008 ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);
2009
2010 ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant);
2011 ath9k_reload_chainmask_settings(sc);
2012
2013 return 0;
2014}
2015
2016static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
2017{
2018 struct ath_softc *sc = hw->priv;
2019
2020 *tx_ant = sc->ant_tx;
2021 *rx_ant = sc->ant_rx;
2022 return 0;
2023}
2024
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302025#ifdef CONFIG_PM_SLEEP
2026
2027static void ath9k_wow_map_triggers(struct ath_softc *sc,
2028 struct cfg80211_wowlan *wowlan,
2029 u32 *wow_triggers)
2030{
2031 if (wowlan->disconnect)
2032 *wow_triggers |= AH_WOW_LINK_CHANGE |
2033 AH_WOW_BEACON_MISS;
2034 if (wowlan->magic_pkt)
2035 *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
2036
2037 if (wowlan->n_patterns)
2038 *wow_triggers |= AH_WOW_USER_PATTERN_EN;
2039
2040 sc->wow_enabled = *wow_triggers;
2041
2042}
2043
2044static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
2045{
2046 struct ath_hw *ah = sc->sc_ah;
2047 struct ath_common *common = ath9k_hw_common(ah);
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302048 int pattern_count = 0;
2049 int i, byte_cnt;
2050 u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
2051 u8 dis_deauth_mask[MAX_PATTERN_SIZE];
2052
2053 memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE);
2054 memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE);
2055
2056 /*
2057 * Create Dissassociate / Deauthenticate packet filter
2058 *
2059 * 2 bytes 2 byte 6 bytes 6 bytes 6 bytes
2060 * +--------------+----------+---------+--------+--------+----
2061 * + Frame Control+ Duration + DA + SA + BSSID +
2062 * +--------------+----------+---------+--------+--------+----
2063 *
2064 * The above is the management frame format for disassociate/
2065 * deauthenticate pattern, from this we need to match the first byte
2066 * of 'Frame Control' and DA, SA, and BSSID fields
2067 * (skipping 2nd byte of FC and Duration feild.
2068 *
2069 * Disassociate pattern
2070 * --------------------
2071 * Frame control = 00 00 1010
2072 * DA, SA, BSSID = x:x:x:x:x:x
2073 * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x
2074 * | x:x:x:x:x:x -- 22 bytes
2075 *
2076 * Deauthenticate pattern
2077 * ----------------------
2078 * Frame control = 00 00 1100
2079 * DA, SA, BSSID = x:x:x:x:x:x
2080 * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x
2081 * | x:x:x:x:x:x -- 22 bytes
2082 */
2083
2084 /* Create Disassociate Pattern first */
2085
2086 byte_cnt = 0;
2087
2088 /* Fill out the mask with all FF's */
2089
2090 for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++)
2091 dis_deauth_mask[i] = 0xff;
2092
2093 /* copy the first byte of frame control field */
2094 dis_deauth_pattern[byte_cnt] = 0xa0;
2095 byte_cnt++;
2096
2097 /* skip 2nd byte of frame control and Duration field */
2098 byte_cnt += 3;
2099
2100 /*
2101 * need not match the destination mac address, it can be a broadcast
2102 * mac address or an unicast to this station
2103 */
2104 byte_cnt += 6;
2105
2106 /* copy the source mac address */
2107 memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
2108
2109 byte_cnt += 6;
2110
2111 /* copy the bssid, its same as the source mac address */
2112
2113 memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
2114
2115 /* Create Disassociate pattern mask */
2116
Sujith Manoharan846e4382013-06-03 09:19:24 +05302117 dis_deauth_mask[0] = 0xfe;
2118 dis_deauth_mask[1] = 0x03;
2119 dis_deauth_mask[2] = 0xc0;
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302120
2121 ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");
2122
2123 ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
2124 pattern_count, byte_cnt);
2125
2126 pattern_count++;
2127 /*
2128 * for de-authenticate pattern, only the first byte of the frame
2129 * control field gets changed from 0xA0 to 0xC0
2130 */
2131 dis_deauth_pattern[0] = 0xC0;
2132
2133 ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
2134 pattern_count, byte_cnt);
2135
2136}
2137
2138static void ath9k_wow_add_pattern(struct ath_softc *sc,
2139 struct cfg80211_wowlan *wowlan)
2140{
2141 struct ath_hw *ah = sc->sc_ah;
2142 struct ath9k_wow_pattern *wow_pattern = NULL;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07002143 struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302144 int mask_len;
2145 s8 i = 0;
2146
2147 if (!wowlan->n_patterns)
2148 return;
2149
2150 /*
2151 * Add the new user configured patterns
2152 */
2153 for (i = 0; i < wowlan->n_patterns; i++) {
2154
2155 wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL);
2156
2157 if (!wow_pattern)
2158 return;
2159
2160 /*
2161 * TODO: convert the generic user space pattern to
2162 * appropriate chip specific/802.11 pattern.
2163 */
2164
2165 mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
2166 memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE);
2167 memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE);
2168 memcpy(wow_pattern->pattern_bytes, patterns[i].pattern,
2169 patterns[i].pattern_len);
2170 memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len);
2171 wow_pattern->pattern_len = patterns[i].pattern_len;
2172
2173 /*
2174 * just need to take care of deauth and disssoc pattern,
2175 * make sure we don't overwrite them.
2176 */
2177
2178 ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes,
2179 wow_pattern->mask_bytes,
2180 i + 2,
2181 wow_pattern->pattern_len);
2182 kfree(wow_pattern);
2183
2184 }
2185
2186}
2187
2188static int ath9k_suspend(struct ieee80211_hw *hw,
2189 struct cfg80211_wowlan *wowlan)
2190{
2191 struct ath_softc *sc = hw->priv;
2192 struct ath_hw *ah = sc->sc_ah;
2193 struct ath_common *common = ath9k_hw_common(ah);
2194 u32 wow_triggers_enabled = 0;
2195 int ret = 0;
2196
2197 mutex_lock(&sc->mutex);
2198
2199 ath_cancel_work(sc);
Mohammed Shafi Shajakhan5686cac2012-09-04 19:33:34 +05302200 ath_stop_ani(sc);
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302201 del_timer_sync(&sc->rx_poll_timer);
2202
2203 if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
2204 ath_dbg(common, ANY, "Device not present\n");
2205 ret = -EINVAL;
2206 goto fail_wow;
2207 }
2208
2209 if (WARN_ON(!wowlan)) {
2210 ath_dbg(common, WOW, "None of the WoW triggers enabled\n");
2211 ret = -EINVAL;
2212 goto fail_wow;
2213 }
2214
2215 if (!device_can_wakeup(sc->dev)) {
2216 ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n");
2217 ret = 1;
2218 goto fail_wow;
2219 }
2220
2221 /*
2222 * none of the sta vifs are associated
2223 * and we are not currently handling multivif
2224 * cases, for instance we have to seperately
2225 * configure 'keep alive frame' for each
2226 * STA.
2227 */
2228
2229 if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
2230 ath_dbg(common, WOW, "None of the STA vifs are associated\n");
2231 ret = 1;
2232 goto fail_wow;
2233 }
2234
2235 if (sc->nvifs > 1) {
2236 ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
2237 ret = 1;
2238 goto fail_wow;
2239 }
2240
2241 ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled);
2242
2243 ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n",
2244 wow_triggers_enabled);
2245
2246 ath9k_ps_wakeup(sc);
2247
2248 ath9k_stop_btcoex(sc);
2249
2250 /*
2251 * Enable wake up on recieving disassoc/deauth
2252 * frame by default.
2253 */
2254 ath9k_wow_add_disassoc_deauth_pattern(sc);
2255
2256 if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN)
2257 ath9k_wow_add_pattern(sc, wowlan);
2258
2259 spin_lock_bh(&sc->sc_pcu_lock);
2260 /*
2261 * To avoid false wake, we enable beacon miss interrupt only
2262 * when we go to sleep. We save the current interrupt mask
2263 * so we can restore it after the system wakes up
2264 */
2265 sc->wow_intr_before_sleep = ah->imask;
2266 ah->imask &= ~ATH9K_INT_GLOBAL;
2267 ath9k_hw_disable_interrupts(ah);
2268 ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL;
2269 ath9k_hw_set_interrupts(ah);
2270 ath9k_hw_enable_interrupts(ah);
2271
2272 spin_unlock_bh(&sc->sc_pcu_lock);
2273
2274 /*
2275 * we can now sync irq and kill any running tasklets, since we already
2276 * disabled interrupts and not holding a spin lock
2277 */
2278 synchronize_irq(sc->irq);
2279 tasklet_kill(&sc->intr_tq);
2280
2281 ath9k_hw_wow_enable(ah, wow_triggers_enabled);
2282
2283 ath9k_ps_restore(sc);
2284 ath_dbg(common, ANY, "WoW enabled in ath9k\n");
2285 atomic_inc(&sc->wow_sleep_proc_intr);
2286
2287fail_wow:
2288 mutex_unlock(&sc->mutex);
2289 return ret;
2290}
2291
2292static int ath9k_resume(struct ieee80211_hw *hw)
2293{
2294 struct ath_softc *sc = hw->priv;
2295 struct ath_hw *ah = sc->sc_ah;
2296 struct ath_common *common = ath9k_hw_common(ah);
2297 u32 wow_status;
2298
2299 mutex_lock(&sc->mutex);
2300
2301 ath9k_ps_wakeup(sc);
2302
2303 spin_lock_bh(&sc->sc_pcu_lock);
2304
2305 ath9k_hw_disable_interrupts(ah);
2306 ah->imask = sc->wow_intr_before_sleep;
2307 ath9k_hw_set_interrupts(ah);
2308 ath9k_hw_enable_interrupts(ah);
2309
2310 spin_unlock_bh(&sc->sc_pcu_lock);
2311
2312 wow_status = ath9k_hw_wow_wakeup(ah);
2313
2314 if (atomic_read(&sc->wow_got_bmiss_intr) == 0) {
2315 /*
2316 * some devices may not pick beacon miss
2317 * as the reason they woke up so we add
2318 * that here for that shortcoming.
2319 */
2320 wow_status |= AH_WOW_BEACON_MISS;
2321 atomic_dec(&sc->wow_got_bmiss_intr);
2322 ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n");
2323 }
2324
2325 atomic_dec(&sc->wow_sleep_proc_intr);
2326
2327 if (wow_status) {
2328 ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n",
2329 ath9k_hw_wow_event_to_string(wow_status), wow_status);
2330 }
2331
2332 ath_restart_work(sc);
2333 ath9k_start_btcoex(sc);
2334
2335 ath9k_ps_restore(sc);
2336 mutex_unlock(&sc->mutex);
2337
2338 return 0;
2339}
2340
2341static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
2342{
2343 struct ath_softc *sc = hw->priv;
2344
2345 mutex_lock(&sc->mutex);
2346 device_init_wakeup(sc->dev, 1);
2347 device_set_wakeup_enable(sc->dev, enabled);
2348 mutex_unlock(&sc->mutex);
2349}
2350
2351#endif
Simon Wunderliche93d0832013-01-08 14:48:58 +01002352static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
2353{
2354 struct ath_softc *sc = hw->priv;
Sujith Manoharan73900cb2013-05-08 05:03:31 +05302355 set_bit(SC_OP_SCANNING, &sc->sc_flags);
Simon Wunderliche93d0832013-01-08 14:48:58 +01002356}
2357
2358static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
2359{
2360 struct ath_softc *sc = hw->priv;
Sujith Manoharan73900cb2013-05-08 05:03:31 +05302361 clear_bit(SC_OP_SCANNING, &sc->sc_flags);
Simon Wunderliche93d0832013-01-08 14:48:58 +01002362}
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302363
Simon Wunderlichd074e8d2013-08-14 08:01:38 +02002364static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw,
2365 struct ieee80211_vif *vif,
2366 struct cfg80211_chan_def *chandef)
2367{
2368 struct ath_softc *sc = hw->priv;
2369
2370 /* mac80211 does not support CSA in multi-if cases (yet) */
2371 if (WARN_ON(sc->csa_vif))
2372 return;
2373
2374 sc->csa_vif = vif;
2375}
2376
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07002377static void ath9k_tx99_stop(struct ath_softc *sc)
2378{
2379 struct ath_hw *ah = sc->sc_ah;
2380 struct ath_common *common = ath9k_hw_common(ah);
2381
2382 ath_drain_all_txq(sc);
2383 ath_startrecv(sc);
2384
2385 ath9k_hw_set_interrupts(ah);
2386 ath9k_hw_enable_interrupts(ah);
2387
2388 ieee80211_wake_queues(sc->hw);
2389
2390 kfree_skb(sc->tx99_skb);
2391 sc->tx99_skb = NULL;
2392 sc->tx99_state = false;
2393
2394 ath9k_hw_tx99_stop(sc->sc_ah);
2395 ath_dbg(common, XMIT, "TX99 stopped\n");
2396}
2397
2398static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
2399{
2400 static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24,
2401 0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50,
2402 0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1,
2403 0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18,
2404 0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8,
2405 0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84,
2406 0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,
2407 0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};
2408 u32 len = 1200;
2409 struct ieee80211_hw *hw = sc->hw;
2410 struct ieee80211_hdr *hdr;
2411 struct ieee80211_tx_info *tx_info;
2412 struct sk_buff *skb;
2413
2414 skb = alloc_skb(len, GFP_KERNEL);
2415 if (!skb)
2416 return NULL;
2417
2418 skb_put(skb, len);
2419
2420 memset(skb->data, 0, len);
2421
2422 hdr = (struct ieee80211_hdr *)skb->data;
2423 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA);
2424 hdr->duration_id = 0;
2425
2426 memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
2427 memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
2428 memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
2429
2430 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
2431
2432 tx_info = IEEE80211_SKB_CB(skb);
2433 memset(tx_info, 0, sizeof(*tx_info));
2434 tx_info->band = hw->conf.chandef.chan->band;
2435 tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
2436 tx_info->control.vif = sc->tx99_vif;
2437
2438 memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data));
2439
2440 return skb;
2441}
2442
2443void ath9k_tx99_deinit(struct ath_softc *sc)
2444{
2445 ath_reset(sc);
2446
2447 ath9k_ps_wakeup(sc);
2448 ath9k_tx99_stop(sc);
2449 ath9k_ps_restore(sc);
2450}
2451
2452int ath9k_tx99_init(struct ath_softc *sc)
2453{
2454 struct ieee80211_hw *hw = sc->hw;
2455 struct ath_hw *ah = sc->sc_ah;
2456 struct ath_common *common = ath9k_hw_common(ah);
2457 struct ath_tx_control txctl;
2458 int r;
2459
2460 if (sc->sc_flags & SC_OP_INVALID) {
2461 ath_err(common,
2462 "driver is in invalid state unable to use TX99");
2463 return -EINVAL;
2464 }
2465
2466 sc->tx99_skb = ath9k_build_tx99_skb(sc);
2467 if (!sc->tx99_skb)
2468 return -ENOMEM;
2469
2470 memset(&txctl, 0, sizeof(txctl));
2471 txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
2472
2473 ath_reset(sc);
2474
2475 ath9k_ps_wakeup(sc);
2476
2477 ath9k_hw_disable_interrupts(ah);
2478 atomic_set(&ah->intr_ref_cnt, -1);
2479 ath_drain_all_txq(sc);
2480 ath_stoprecv(sc);
2481
2482 sc->tx99_state = true;
2483
2484 ieee80211_stop_queues(hw);
2485
2486 if (sc->tx99_power == MAX_RATE_POWER + 1)
2487 sc->tx99_power = MAX_RATE_POWER;
2488
2489 ath9k_hw_tx99_set_txpower(ah, sc->tx99_power);
2490 r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl);
2491 if (r) {
2492 ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n");
2493 return r;
2494 }
2495
2496 ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n",
2497 sc->tx99_power,
2498 sc->tx99_power / 2);
2499
2500 /* We leave the harware awake as it will be chugging on */
2501
2502 return 0;
2503}
2504
Gabor Juhos6baff7f2009-01-14 20:17:06 +01002505struct ieee80211_ops ath9k_ops = {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002506 .tx = ath9k_tx,
2507 .start = ath9k_start,
2508 .stop = ath9k_stop,
2509 .add_interface = ath9k_add_interface,
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05302510 .change_interface = ath9k_change_interface,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002511 .remove_interface = ath9k_remove_interface,
2512 .config = ath9k_config,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002513 .configure_filter = ath9k_configure_filter,
Johannes Berg4ca77862010-02-19 19:06:56 +01002514 .sta_add = ath9k_sta_add,
2515 .sta_remove = ath9k_sta_remove,
Felix Fietkau55195412011-04-17 23:28:09 +02002516 .sta_notify = ath9k_sta_notify,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002517 .conf_tx = ath9k_conf_tx,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002518 .bss_info_changed = ath9k_bss_info_changed,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002519 .set_key = ath9k_set_key,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002520 .get_tsf = ath9k_get_tsf,
Alina Friedrichsen3b5d6652009-01-24 07:09:59 +01002521 .set_tsf = ath9k_set_tsf,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002522 .reset_tsf = ath9k_reset_tsf,
Johannes Berg4233df62008-10-13 13:35:05 +02002523 .ampdu_action = ath9k_ampdu_action,
Benoit Papillault62dad5b2010-04-28 00:08:24 +02002524 .get_survey = ath9k_get_survey,
Johannes Berg3b319aa2009-06-13 14:50:26 +05302525 .rfkill_poll = ath9k_rfkill_poll_state,
Felix Fietkaue239d852010-01-15 02:34:58 +01002526 .set_coverage_class = ath9k_set_coverage_class,
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08002527 .flush = ath9k_flush,
Vivek Natarajan15b91e82011-04-06 11:41:11 +05302528 .tx_frames_pending = ath9k_tx_frames_pending,
Mohammed Shafi Shajakhan52c94f42011-08-20 17:21:42 +05302529 .tx_last_beacon = ath9k_tx_last_beacon,
Felix Fietkau86a22ac2013-06-07 18:12:01 +02002530 .release_buffered_frames = ath9k_release_buffered_frames,
Mohammed Shafi Shajakhan52c94f42011-08-20 17:21:42 +05302531 .get_stats = ath9k_get_stats,
Felix Fietkau43c35282011-09-03 01:40:27 +02002532 .set_antenna = ath9k_set_antenna,
2533 .get_antenna = ath9k_get_antenna,
Ben Greearb90bd9d2012-05-15 15:33:25 -07002534
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302535#ifdef CONFIG_PM_SLEEP
2536 .suspend = ath9k_suspend,
2537 .resume = ath9k_resume,
2538 .set_wakeup = ath9k_set_wakeup,
2539#endif
2540
Ben Greearb90bd9d2012-05-15 15:33:25 -07002541#ifdef CONFIG_ATH9K_DEBUGFS
2542 .get_et_sset_count = ath9k_get_et_sset_count,
Sujith Manoharana145daf2012-11-28 15:08:54 +05302543 .get_et_stats = ath9k_get_et_stats,
2544 .get_et_strings = ath9k_get_et_strings,
2545#endif
2546
2547#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
2548 .sta_add_debugfs = ath9k_sta_add_debugfs,
Ben Greearb90bd9d2012-05-15 15:33:25 -07002549#endif
Simon Wunderliche93d0832013-01-08 14:48:58 +01002550 .sw_scan_start = ath9k_sw_scan_start,
2551 .sw_scan_complete = ath9k_sw_scan_complete,
Simon Wunderlichd074e8d2013-08-14 08:01:38 +02002552 .channel_switch_beacon = ath9k_channel_switch_beacon,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002553};