blob: 74f452c7b1667c47a65506a077042f2b0668c3a8 [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 /*
968 * Use the hardware MAC address as reference, the hardware uses it
969 * together with the BSSID mask when matching addresses.
970 */
971 memset(iter_data, 0, sizeof(*iter_data));
Ben Greear48014162011-01-15 19:13:48 +0000972 memset(&iter_data->mask, 0xff, ETH_ALEN);
973
974 if (vif)
975 ath9k_vif_iter(iter_data, vif->addr, vif);
976
977 /* Get list of all active MAC addresses */
Johannes Berg8b2c9822012-11-06 20:23:30 +0100978 ieee80211_iterate_active_interfaces_atomic(
979 sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
980 ath9k_vif_iter, iter_data);
Felix Fietkauab11bb22013-04-16 12:51:57 +0200981
982 memcpy(common->macaddr, iter_data->hw_macaddr, ETH_ALEN);
Ben Greear48014162011-01-15 19:13:48 +0000983}
984
985/* Called with sc->mutex held. */
986static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
987 struct ieee80211_vif *vif)
988{
Felix Fietkau9ac586152011-01-24 19:23:18 +0100989 struct ath_softc *sc = hw->priv;
Ben Greear48014162011-01-15 19:13:48 +0000990 struct ath_hw *ah = sc->sc_ah;
991 struct ath_common *common = ath9k_hw_common(ah);
992 struct ath9k_vif_iter_data iter_data;
Sujith Manoharan6dcc3442012-07-17 17:16:36 +0530993 enum nl80211_iftype old_opmode = ah->opmode;
Ben Greear48014162011-01-15 19:13:48 +0000994
995 ath9k_calculate_iter_data(hw, vif, &iter_data);
996
Ben Greear48014162011-01-15 19:13:48 +0000997 memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
998 ath_hw_setbssidmask(common);
999
Ben Greear48014162011-01-15 19:13:48 +00001000 if (iter_data.naps > 0) {
Sujith Manoharan60ca9f82012-07-17 17:15:37 +05301001 ath9k_hw_set_tsfadjust(ah, true);
Ben Greear48014162011-01-15 19:13:48 +00001002 ah->opmode = NL80211_IFTYPE_AP;
1003 } else {
Sujith Manoharan60ca9f82012-07-17 17:15:37 +05301004 ath9k_hw_set_tsfadjust(ah, false);
Ben Greear48014162011-01-15 19:13:48 +00001005
Javier Cardonafd5999c2011-05-03 16:57:19 -07001006 if (iter_data.nmeshes)
1007 ah->opmode = NL80211_IFTYPE_MESH_POINT;
1008 else if (iter_data.nwds)
Ben Greear48014162011-01-15 19:13:48 +00001009 ah->opmode = NL80211_IFTYPE_AP;
1010 else if (iter_data.nadhocs)
1011 ah->opmode = NL80211_IFTYPE_ADHOC;
1012 else
1013 ah->opmode = NL80211_IFTYPE_STATION;
1014 }
1015
Sujith Manoharandf35d292012-07-17 17:15:43 +05301016 ath9k_hw_setopmode(ah);
1017
Felix Fietkau198823f2012-06-15 15:25:25 +02001018 if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0)
Ben Greear48014162011-01-15 19:13:48 +00001019 ah->imask |= ATH9K_INT_TSFOOR;
Felix Fietkau198823f2012-06-15 15:25:25 +02001020 else
Ben Greear48014162011-01-15 19:13:48 +00001021 ah->imask &= ~ATH9K_INT_TSFOOR;
Ben Greear48014162011-01-15 19:13:48 +00001022
Felix Fietkau72d874c2011-10-08 20:06:19 +02001023 ath9k_hw_set_interrupts(ah);
Sujith Manoharan6dcc3442012-07-17 17:16:36 +05301024
1025 /*
1026 * If we are changing the opmode to STATION,
1027 * a beacon sync needs to be done.
1028 */
1029 if (ah->opmode == NL80211_IFTYPE_STATION &&
1030 old_opmode == NL80211_IFTYPE_AP &&
1031 test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
Johannes Berg8b2c9822012-11-06 20:23:30 +01001032 ieee80211_iterate_active_interfaces_atomic(
1033 sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
1034 ath9k_sta_vif_iter, sc);
Sujith Manoharan6dcc3442012-07-17 17:16:36 +05301035 }
Ben Greear48014162011-01-15 19:13:48 +00001036}
1037
Ben Greear48014162011-01-15 19:13:48 +00001038static int ath9k_add_interface(struct ieee80211_hw *hw,
1039 struct ieee80211_vif *vif)
1040{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001041 struct ath_softc *sc = hw->priv;
Ben Greear48014162011-01-15 19:13:48 +00001042 struct ath_hw *ah = sc->sc_ah;
1043 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkauf89d1bc2013-08-06 14:18:13 +02001044 struct ath_vif *avp = (void *)vif->drv_priv;
1045 struct ath_node *an = &avp->mcast_node;
Ben Greear48014162011-01-15 19:13:48 +00001046
1047 mutex_lock(&sc->mutex);
1048
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001049 if (config_enabled(CONFIG_ATH9K_TX99)) {
1050 if (sc->nvifs >= 1) {
1051 mutex_unlock(&sc->mutex);
1052 return -EOPNOTSUPP;
1053 }
1054 sc->tx99_vif = vif;
1055 }
1056
Joe Perchesd2182b62011-12-15 14:55:53 -08001057 ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
Ben Greear48014162011-01-15 19:13:48 +00001058 sc->nvifs++;
1059
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301060 ath9k_ps_wakeup(sc);
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301061 ath9k_calculate_summary_state(hw, vif);
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301062 ath9k_ps_restore(sc);
1063
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301064 if (ath9k_uses_beacons(vif->type))
1065 ath9k_beacon_assign_slot(sc, vif);
1066
Felix Fietkauf89d1bc2013-08-06 14:18:13 +02001067 an->sc = sc;
1068 an->sta = NULL;
1069 an->vif = vif;
1070 an->no_ps_filter = true;
1071 ath_tx_node_init(sc, an);
1072
Ben Greear48014162011-01-15 19:13:48 +00001073 mutex_unlock(&sc->mutex);
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301074 return 0;
Ben Greear48014162011-01-15 19:13:48 +00001075}
1076
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301077static int ath9k_change_interface(struct ieee80211_hw *hw,
1078 struct ieee80211_vif *vif,
1079 enum nl80211_iftype new_type,
1080 bool p2p)
1081{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001082 struct ath_softc *sc = hw->priv;
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301083 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1084
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301085 mutex_lock(&sc->mutex);
Ben Greear48014162011-01-15 19:13:48 +00001086
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001087 if (config_enabled(CONFIG_ATH9K_TX99)) {
1088 mutex_unlock(&sc->mutex);
1089 return -EOPNOTSUPP;
1090 }
1091
1092 ath_dbg(common, CONFIG, "Change Interface\n");
1093
Ben Greear48014162011-01-15 19:13:48 +00001094 if (ath9k_uses_beacons(vif->type))
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301095 ath9k_beacon_remove_slot(sc, vif);
Ben Greear48014162011-01-15 19:13:48 +00001096
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301097 vif->type = new_type;
1098 vif->p2p = p2p;
1099
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301100 ath9k_ps_wakeup(sc);
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301101 ath9k_calculate_summary_state(hw, vif);
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301102 ath9k_ps_restore(sc);
1103
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301104 if (ath9k_uses_beacons(vif->type))
1105 ath9k_beacon_assign_slot(sc, vif);
1106
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301107 mutex_unlock(&sc->mutex);
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301108 return 0;
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301109}
1110
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001111static void ath9k_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001112 struct ieee80211_vif *vif)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001113{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001114 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001115 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkauf89d1bc2013-08-06 14:18:13 +02001116 struct ath_vif *avp = (void *)vif->drv_priv;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001117
Joe Perchesd2182b62011-12-15 14:55:53 -08001118 ath_dbg(common, CONFIG, "Detach Interface\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001119
Sujith141b38b2009-02-04 08:10:07 +05301120 mutex_lock(&sc->mutex);
1121
Ben Greear48014162011-01-15 19:13:48 +00001122 sc->nvifs--;
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001123 sc->tx99_vif = NULL;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001124
Ben Greear48014162011-01-15 19:13:48 +00001125 if (ath9k_uses_beacons(vif->type))
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301126 ath9k_beacon_remove_slot(sc, vif);
Jouni Malinen2c3db3d2009-03-03 19:23:26 +02001127
Simon Wunderlichd074e8d2013-08-14 08:01:38 +02001128 if (sc->csa_vif == vif)
1129 sc->csa_vif = NULL;
1130
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301131 ath9k_ps_wakeup(sc);
Ben Greear48014162011-01-15 19:13:48 +00001132 ath9k_calculate_summary_state(hw, NULL);
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301133 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301134
Felix Fietkauf89d1bc2013-08-06 14:18:13 +02001135 ath_tx_node_cleanup(sc, &avp->mcast_node);
1136
Sujith141b38b2009-02-04 08:10:07 +05301137 mutex_unlock(&sc->mutex);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001138}
1139
Senthil Balasubramanianfbab7392010-10-05 20:36:40 +05301140static void ath9k_enable_ps(struct ath_softc *sc)
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301141{
Pavel Roskin30691682010-03-31 18:05:31 -04001142 struct ath_hw *ah = sc->sc_ah;
Sujith Manoharanad128862012-04-24 10:23:20 +05301143 struct ath_common *common = ath9k_hw_common(ah);
Pavel Roskin30691682010-03-31 18:05:31 -04001144
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001145 if (config_enabled(CONFIG_ATH9K_TX99))
1146 return;
1147
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301148 sc->ps_enabled = true;
Pavel Roskin30691682010-03-31 18:05:31 -04001149 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
1150 if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) {
1151 ah->imask |= ATH9K_INT_TIM_TIMER;
Felix Fietkau72d874c2011-10-08 20:06:19 +02001152 ath9k_hw_set_interrupts(ah);
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301153 }
Vasanthakumar Thiagarajanfdf76622010-05-17 18:57:55 -07001154 ath9k_hw_setrxabort(ah, 1);
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301155 }
Sujith Manoharanad128862012-04-24 10:23:20 +05301156 ath_dbg(common, PS, "PowerSave enabled\n");
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301157}
1158
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301159static void ath9k_disable_ps(struct ath_softc *sc)
1160{
1161 struct ath_hw *ah = sc->sc_ah;
Sujith Manoharanad128862012-04-24 10:23:20 +05301162 struct ath_common *common = ath9k_hw_common(ah);
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301163
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001164 if (config_enabled(CONFIG_ATH9K_TX99))
1165 return;
1166
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301167 sc->ps_enabled = false;
1168 ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
1169 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
1170 ath9k_hw_setrxabort(ah, 0);
1171 sc->ps_flags &= ~(PS_WAIT_FOR_BEACON |
1172 PS_WAIT_FOR_CAB |
1173 PS_WAIT_FOR_PSPOLL_DATA |
1174 PS_WAIT_FOR_TX_ACK);
1175 if (ah->imask & ATH9K_INT_TIM_TIMER) {
1176 ah->imask &= ~ATH9K_INT_TIM_TIMER;
Felix Fietkau72d874c2011-10-08 20:06:19 +02001177 ath9k_hw_set_interrupts(ah);
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301178 }
1179 }
Sujith Manoharanad128862012-04-24 10:23:20 +05301180 ath_dbg(common, PS, "PowerSave disabled\n");
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301181}
1182
Simon Wunderliche93d0832013-01-08 14:48:58 +01001183void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw)
1184{
1185 struct ath_softc *sc = hw->priv;
1186 struct ath_hw *ah = sc->sc_ah;
1187 struct ath_common *common = ath9k_hw_common(ah);
1188 u32 rxfilter;
1189
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001190 if (config_enabled(CONFIG_ATH9K_TX99))
1191 return;
1192
Simon Wunderliche93d0832013-01-08 14:48:58 +01001193 if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
1194 ath_err(common, "spectrum analyzer not implemented on this hardware\n");
1195 return;
1196 }
1197
1198 ath9k_ps_wakeup(sc);
1199 rxfilter = ath9k_hw_getrxfilter(ah);
1200 ath9k_hw_setrxfilter(ah, rxfilter |
1201 ATH9K_RX_FILTER_PHYRADAR |
1202 ATH9K_RX_FILTER_PHYERR);
1203
1204 /* TODO: usually this should not be neccesary, but for some reason
1205 * (or in some mode?) the trigger must be called after the
1206 * configuration, otherwise the register will have its values reset
1207 * (on my ar9220 to value 0x01002310)
1208 */
1209 ath9k_spectral_scan_config(hw, sc->spectral_mode);
1210 ath9k_hw_ops(ah)->spectral_scan_trigger(ah);
1211 ath9k_ps_restore(sc);
1212}
1213
1214int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
1215 enum spectral_mode spectral_mode)
1216{
1217 struct ath_softc *sc = hw->priv;
1218 struct ath_hw *ah = sc->sc_ah;
1219 struct ath_common *common = ath9k_hw_common(ah);
Simon Wunderliche93d0832013-01-08 14:48:58 +01001220
1221 if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
1222 ath_err(common, "spectrum analyzer not implemented on this hardware\n");
1223 return -1;
1224 }
1225
Simon Wunderliche93d0832013-01-08 14:48:58 +01001226 switch (spectral_mode) {
1227 case SPECTRAL_DISABLED:
Simon Wunderlich04ccd4a2013-01-23 17:38:04 +01001228 sc->spec_config.enabled = 0;
Simon Wunderliche93d0832013-01-08 14:48:58 +01001229 break;
1230 case SPECTRAL_BACKGROUND:
1231 /* send endless samples.
1232 * TODO: is this really useful for "background"?
1233 */
Simon Wunderlich04ccd4a2013-01-23 17:38:04 +01001234 sc->spec_config.endless = 1;
1235 sc->spec_config.enabled = 1;
Simon Wunderliche93d0832013-01-08 14:48:58 +01001236 break;
1237 case SPECTRAL_CHANSCAN:
Simon Wunderliche93d0832013-01-08 14:48:58 +01001238 case SPECTRAL_MANUAL:
Simon Wunderlich04ccd4a2013-01-23 17:38:04 +01001239 sc->spec_config.endless = 0;
1240 sc->spec_config.enabled = 1;
Simon Wunderliche93d0832013-01-08 14:48:58 +01001241 break;
1242 default:
1243 return -1;
1244 }
1245
1246 ath9k_ps_wakeup(sc);
Simon Wunderlich04ccd4a2013-01-23 17:38:04 +01001247 ath9k_hw_ops(ah)->spectral_scan_config(ah, &sc->spec_config);
Simon Wunderliche93d0832013-01-08 14:48:58 +01001248 ath9k_ps_restore(sc);
1249
1250 sc->spectral_mode = spectral_mode;
1251
1252 return 0;
1253}
1254
Johannes Berge8975582008-10-09 12:18:51 +02001255static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001256{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001257 struct ath_softc *sc = hw->priv;
Felix Fietkau34300982010-10-10 18:21:52 +02001258 struct ath_hw *ah = sc->sc_ah;
1259 struct ath_common *common = ath9k_hw_common(ah);
Johannes Berge8975582008-10-09 12:18:51 +02001260 struct ieee80211_conf *conf = &hw->conf;
Felix Fietkau75600ab2012-04-12 20:36:31 +02001261 bool reset_channel = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001262
Felix Fietkauc0c11742011-11-16 13:08:41 +01001263 ath9k_ps_wakeup(sc);
Sujithaa33de02008-12-18 11:40:16 +05301264 mutex_lock(&sc->mutex);
Sujith141b38b2009-02-04 08:10:07 +05301265
Felix Fietkaudaa1b6e2011-11-16 13:08:43 +01001266 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Felix Fietkau7545daf2011-01-24 19:23:16 +01001267 sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
Rajkumar Manoharanb73f3e72012-07-01 19:53:53 +05301268 if (sc->ps_idle) {
Felix Fietkaudaa1b6e2011-11-16 13:08:43 +01001269 ath_cancel_work(sc);
Rajkumar Manoharanb73f3e72012-07-01 19:53:53 +05301270 ath9k_stop_btcoex(sc);
1271 } else {
1272 ath9k_start_btcoex(sc);
Felix Fietkau75600ab2012-04-12 20:36:31 +02001273 /*
1274 * The chip needs a reset to properly wake up from
1275 * full sleep
1276 */
1277 reset_channel = ah->chip_fullsleep;
Rajkumar Manoharanb73f3e72012-07-01 19:53:53 +05301278 }
Felix Fietkaudaa1b6e2011-11-16 13:08:43 +01001279 }
Luis R. Rodriguez64839172009-07-14 20:22:53 -04001280
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001281 /*
1282 * We just prepare to enable PS. We have to wait until our AP has
1283 * ACK'd our null data frame to disable RX otherwise we'll ignore
1284 * those ACKs and end up retransmitting the same null data frames.
1285 * IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode.
1286 */
Vivek Natarajan3cbb5dd2009-01-20 11:17:08 +05301287 if (changed & IEEE80211_CONF_CHANGE_PS) {
Luis R. Rodriguez8ab2cd02010-09-16 15:12:26 -04001288 unsigned long flags;
1289 spin_lock_irqsave(&sc->sc_pm_lock, flags);
Senthil Balasubramanianfbab7392010-10-05 20:36:40 +05301290 if (conf->flags & IEEE80211_CONF_PS)
1291 ath9k_enable_ps(sc);
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301292 else
1293 ath9k_disable_ps(sc);
Luis R. Rodriguez8ab2cd02010-09-16 15:12:26 -04001294 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
Vivek Natarajan3cbb5dd2009-01-20 11:17:08 +05301295 }
1296
Sujith199afd92010-01-08 10:36:13 +05301297 if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
1298 if (conf->flags & IEEE80211_CONF_MONITOR) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001299 ath_dbg(common, CONFIG, "Monitor mode is enabled\n");
Rajkumar Manoharan5f841b42010-10-27 18:31:15 +05301300 sc->sc_ah->is_monitoring = true;
1301 } else {
Joe Perchesd2182b62011-12-15 14:55:53 -08001302 ath_dbg(common, CONFIG, "Monitor mode is disabled\n");
Rajkumar Manoharan5f841b42010-10-27 18:31:15 +05301303 sc->sc_ah->is_monitoring = false;
Sujith199afd92010-01-08 10:36:13 +05301304 }
1305 }
1306
Felix Fietkau75600ab2012-04-12 20:36:31 +02001307 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) {
Felix Fietkau45c67f62013-10-11 23:30:58 +02001308 if (ath_set_channel(sc, &hw->conf.chandef) < 0) {
Joe Perches38002762010-12-02 19:12:36 -08001309 ath_err(common, "Unable to set channel\n");
Sujithaa33de02008-12-18 11:40:16 +05301310 mutex_unlock(&sc->mutex);
Rajkumar Manoharan8389fb32012-06-11 12:19:30 +05301311 ath9k_ps_restore(sc);
Sujithe11602b2008-11-27 09:46:27 +05301312 return -EINVAL;
1313 }
Sujith094d05d2008-12-12 11:57:43 +05301314 }
Sujith86b89ee2008-08-07 10:54:57 +05301315
Luis R. Rodriguezc9f6a652010-01-19 14:04:19 -05001316 if (changed & IEEE80211_CONF_CHANGE_POWER) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001317 ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level);
Sujith17d79042009-02-09 13:27:03 +05301318 sc->config.txpowlimit = 2 * conf->power_level;
Rajkumar Manoharan5048e8c2011-01-31 23:47:44 +05301319 ath9k_cmn_update_txpow(ah, sc->curtxpow,
1320 sc->config.txpowlimit, &sc->curtxpow);
Luis R. Rodriguez64839172009-07-14 20:22:53 -04001321 }
1322
Sujithaa33de02008-12-18 11:40:16 +05301323 mutex_unlock(&sc->mutex);
Felix Fietkauc0c11742011-11-16 13:08:41 +01001324 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301325
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001326 return 0;
1327}
1328
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001329#define SUPPORTED_FILTERS \
1330 (FIF_PROMISC_IN_BSS | \
1331 FIF_ALLMULTI | \
1332 FIF_CONTROL | \
Luis R. Rodriguezaf6a3fc2009-08-08 21:55:16 -04001333 FIF_PSPOLL | \
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001334 FIF_OTHER_BSS | \
1335 FIF_BCN_PRBRESP_PROMISC | \
Jouni Malinen9c1d8e42010-10-13 17:29:31 +03001336 FIF_PROBE_REQ | \
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001337 FIF_FCSFAIL)
1338
Sujith7dcfdcd2008-08-11 14:03:13 +05301339/* FIXME: sc->sc_full_reset ? */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001340static void ath9k_configure_filter(struct ieee80211_hw *hw,
1341 unsigned int changed_flags,
1342 unsigned int *total_flags,
Johannes Berg3ac64be2009-08-17 16:16:53 +02001343 u64 multicast)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001344{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001345 struct ath_softc *sc = hw->priv;
Sujith7dcfdcd2008-08-11 14:03:13 +05301346 u32 rfilt;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001347
1348 changed_flags &= SUPPORTED_FILTERS;
1349 *total_flags &= SUPPORTED_FILTERS;
1350
Sujithb77f4832008-12-07 21:44:03 +05301351 sc->rx.rxfilter = *total_flags;
Jouni Malinenaa68aea2009-05-19 17:01:41 +03001352 ath9k_ps_wakeup(sc);
Sujith7dcfdcd2008-08-11 14:03:13 +05301353 rfilt = ath_calcrxfilter(sc);
1354 ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
Jouni Malinenaa68aea2009-05-19 17:01:41 +03001355 ath9k_ps_restore(sc);
Sujith7dcfdcd2008-08-11 14:03:13 +05301356
Joe Perchesd2182b62011-12-15 14:55:53 -08001357 ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG, "Set HW RX filter: 0x%x\n",
1358 rfilt);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001359}
1360
Johannes Berg4ca77862010-02-19 19:06:56 +01001361static int ath9k_sta_add(struct ieee80211_hw *hw,
1362 struct ieee80211_vif *vif,
1363 struct ieee80211_sta *sta)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001364{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001365 struct ath_softc *sc = hw->priv;
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001366 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1367 struct ath_node *an = (struct ath_node *) sta->drv_priv;
1368 struct ieee80211_key_conf ps_key = { };
Felix Fietkau4ef69d02013-04-27 11:47:01 +02001369 int key;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001370
Ben Greear7e1e3862011-11-03 11:33:13 -07001371 ath_node_attach(sc, sta, vif);
Felix Fietkauf59a59f2011-05-10 20:52:22 +02001372
1373 if (vif->type != NL80211_IFTYPE_AP &&
1374 vif->type != NL80211_IFTYPE_AP_VLAN)
1375 return 0;
1376
Felix Fietkau4ef69d02013-04-27 11:47:01 +02001377 key = ath_key_config(common, vif, sta, &ps_key);
1378 if (key > 0)
1379 an->ps_key = key;
Johannes Berg4ca77862010-02-19 19:06:56 +01001380
1381 return 0;
1382}
1383
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001384static void ath9k_del_ps_key(struct ath_softc *sc,
1385 struct ieee80211_vif *vif,
1386 struct ieee80211_sta *sta)
1387{
1388 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1389 struct ath_node *an = (struct ath_node *) sta->drv_priv;
1390 struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key };
1391
1392 if (!an->ps_key)
1393 return;
1394
1395 ath_key_delete(common, &ps_key);
Felix Fietkau4ef69d02013-04-27 11:47:01 +02001396 an->ps_key = 0;
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001397}
1398
Johannes Berg4ca77862010-02-19 19:06:56 +01001399static int ath9k_sta_remove(struct ieee80211_hw *hw,
1400 struct ieee80211_vif *vif,
1401 struct ieee80211_sta *sta)
1402{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001403 struct ath_softc *sc = hw->priv;
Johannes Berg4ca77862010-02-19 19:06:56 +01001404
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001405 ath9k_del_ps_key(sc, vif, sta);
Johannes Berg4ca77862010-02-19 19:06:56 +01001406 ath_node_detach(sc, sta);
1407
1408 return 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001409}
1410
Felix Fietkau55195412011-04-17 23:28:09 +02001411static void ath9k_sta_notify(struct ieee80211_hw *hw,
1412 struct ieee80211_vif *vif,
1413 enum sta_notify_cmd cmd,
1414 struct ieee80211_sta *sta)
1415{
1416 struct ath_softc *sc = hw->priv;
1417 struct ath_node *an = (struct ath_node *) sta->drv_priv;
1418
1419 switch (cmd) {
1420 case STA_NOTIFY_SLEEP:
1421 an->sleeping = true;
Johannes Berg042ec452011-09-29 16:04:26 +02001422 ath_tx_aggr_sleep(sta, sc, an);
Felix Fietkau55195412011-04-17 23:28:09 +02001423 break;
1424 case STA_NOTIFY_AWAKE:
1425 an->sleeping = false;
1426 ath_tx_aggr_wakeup(sc, an);
1427 break;
1428 }
1429}
1430
Eliad Peller8a3a3c82011-10-02 10:15:52 +02001431static int ath9k_conf_tx(struct ieee80211_hw *hw,
1432 struct ieee80211_vif *vif, u16 queue,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001433 const struct ieee80211_tx_queue_params *params)
1434{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001435 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001436 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau066dae92010-11-07 14:59:39 +01001437 struct ath_txq *txq;
Sujithea9880f2008-08-07 10:53:10 +05301438 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +01001439 int ret = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001440
Sujith Manoharanbea843c2012-11-21 18:13:10 +05301441 if (queue >= IEEE80211_NUM_ACS)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001442 return 0;
1443
Felix Fietkau066dae92010-11-07 14:59:39 +01001444 txq = sc->tx.txq_map[queue];
1445
Felix Fietkau96f372c2011-04-07 19:07:17 +02001446 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301447 mutex_lock(&sc->mutex);
1448
Sujith1ffb0612009-03-30 15:28:46 +05301449 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
1450
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001451 qi.tqi_aifs = params->aifs;
1452 qi.tqi_cwmin = params->cw_min;
1453 qi.tqi_cwmax = params->cw_max;
Felix Fietkau531bd072012-07-15 19:53:34 +02001454 qi.tqi_burstTime = params->txop * 32;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001455
Joe Perchesd2182b62011-12-15 14:55:53 -08001456 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -08001457 "Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
1458 queue, txq->axq_qnum, params->aifs, params->cw_min,
1459 params->cw_max, params->txop);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001460
Felix Fietkauaa5955c2012-07-15 19:53:36 +02001461 ath_update_max_aggr_framelen(sc, queue, qi.tqi_burstTime);
Felix Fietkau066dae92010-11-07 14:59:39 +01001462 ret = ath_txq_update(sc, txq->axq_qnum, &qi);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001463 if (ret)
Joe Perches38002762010-12-02 19:12:36 -08001464 ath_err(common, "TXQ Update failed\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001465
Sujith141b38b2009-02-04 08:10:07 +05301466 mutex_unlock(&sc->mutex);
Felix Fietkau96f372c2011-04-07 19:07:17 +02001467 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301468
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001469 return ret;
1470}
1471
1472static int ath9k_set_key(struct ieee80211_hw *hw,
1473 enum set_key_cmd cmd,
Johannes Bergdc822b52008-12-29 12:55:09 +01001474 struct ieee80211_vif *vif,
1475 struct ieee80211_sta *sta,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001476 struct ieee80211_key_conf *key)
1477{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001478 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001479 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001480 int ret = 0;
1481
John W. Linville3e6109c2011-01-05 09:39:17 -05001482 if (ath9k_modparam_nohwcrypt)
Jouni Malinenb3bd89c2009-02-24 13:42:01 +02001483 return -ENOSPC;
1484
Chun-Yeow Yeoh5bd5e9a2011-12-07 12:45:46 -08001485 if ((vif->type == NL80211_IFTYPE_ADHOC ||
1486 vif->type == NL80211_IFTYPE_MESH_POINT) &&
Jouni Malinencfdc9a82011-03-23 14:52:19 +02001487 (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
1488 key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
1489 !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
1490 /*
1491 * For now, disable hw crypto for the RSN IBSS group keys. This
1492 * could be optimized in the future to use a modified key cache
1493 * design to support per-STA RX GTK, but until that gets
1494 * implemented, use of software crypto for group addressed
1495 * frames is a acceptable to allow RSN IBSS to be used.
1496 */
1497 return -EOPNOTSUPP;
1498 }
1499
Sujith141b38b2009-02-04 08:10:07 +05301500 mutex_lock(&sc->mutex);
Vivek Natarajan3cbb5dd2009-01-20 11:17:08 +05301501 ath9k_ps_wakeup(sc);
Joe Perchesd2182b62011-12-15 14:55:53 -08001502 ath_dbg(common, CONFIG, "Set HW Key\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001503
1504 switch (cmd) {
1505 case SET_KEY:
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001506 if (sta)
1507 ath9k_del_ps_key(sc, vif, sta);
1508
Bruno Randolf040e5392010-09-08 16:05:04 +09001509 ret = ath_key_config(common, vif, sta, key);
Jouni Malinen6ace2892008-12-17 13:32:17 +02001510 if (ret >= 0) {
1511 key->hw_key_idx = ret;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001512 /* push IV and Michael MIC generation to stack */
1513 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Johannes Berg97359d12010-08-10 09:46:38 +02001514 if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
Senthil Balasubramanian1b961752008-09-01 19:45:21 +05301515 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
Johannes Berg97359d12010-08-10 09:46:38 +02001516 if (sc->sc_ah->sw_mgmt_crypto &&
1517 key->cipher == WLAN_CIPHER_SUITE_CCMP)
Johannes Berge548c492012-09-04 17:08:23 +02001518 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
Jouni Malinen6ace2892008-12-17 13:32:17 +02001519 ret = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001520 }
1521 break;
1522 case DISABLE_KEY:
Bruno Randolf040e5392010-09-08 16:05:04 +09001523 ath_key_delete(common, key);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001524 break;
1525 default:
1526 ret = -EINVAL;
1527 }
1528
Vivek Natarajan3cbb5dd2009-01-20 11:17:08 +05301529 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301530 mutex_unlock(&sc->mutex);
1531
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001532 return ret;
1533}
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301534
1535static void ath9k_set_assoc_state(struct ath_softc *sc,
1536 struct ieee80211_vif *vif)
Rajkumar Manoharan4f5ef75b2011-04-04 22:56:18 +05301537{
Rajkumar Manoharan4f5ef75b2011-04-04 22:56:18 +05301538 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Rajkumar Manoharan4f5ef75b2011-04-04 22:56:18 +05301539 struct ath_vif *avp = (void *)vif->drv_priv;
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301540 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Sujith Manoharan07c15a32012-06-04 20:24:07 +05301541 unsigned long flags;
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301542
1543 set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
1544 avp->primary_sta_vif = true;
1545
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301546 /*
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301547 * Set the AID, BSSID and do beacon-sync only when
1548 * the HW opmode is STATION.
1549 *
1550 * But the primary bit is set above in any case.
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301551 */
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301552 if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
1553 return;
1554
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301555 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1556 common->curaid = bss_conf->aid;
1557 ath9k_hw_write_associd(sc->sc_ah);
Rajkumar Manoharan4f5ef75b2011-04-04 22:56:18 +05301558
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301559 sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
1560 sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
Rajkumar Manoharan4f5ef75b2011-04-04 22:56:18 +05301561
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301562 spin_lock_irqsave(&sc->sc_pm_lock, flags);
1563 sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
1564 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
1565
Rajkumar Manoharan50072eb2012-10-12 14:07:22 +05301566 if (ath9k_hw_mci_is_enabled(sc->sc_ah))
1567 ath9k_mci_update_wlan_channels(sc, false);
1568
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301569 ath_dbg(common, CONFIG,
1570 "Primary Station interface: %pM, BSSID: %pM\n",
1571 vif->addr, common->curbssid);
1572}
1573
1574static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
1575{
1576 struct ath_softc *sc = data;
1577 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
1578
1579 if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
1580 return;
1581
1582 if (bss_conf->assoc)
1583 ath9k_set_assoc_state(sc, vif);
Rajkumar Manoharan4f5ef75b2011-04-04 22:56:18 +05301584}
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001585
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001586static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
1587 struct ieee80211_vif *vif,
1588 struct ieee80211_bss_conf *bss_conf,
1589 u32 changed)
1590{
Sujith Manoharanda0d45f2012-07-17 17:16:29 +05301591#define CHECK_ANI \
1592 (BSS_CHANGED_ASSOC | \
1593 BSS_CHANGED_IBSS | \
1594 BSS_CHANGED_BEACON_ENABLED)
1595
Felix Fietkau9ac586152011-01-24 19:23:18 +01001596 struct ath_softc *sc = hw->priv;
Johannes Berg2d0ddec2009-04-23 16:13:26 +02001597 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguez15107182009-09-10 09:22:37 -07001598 struct ath_common *common = ath9k_hw_common(ah);
Johannes Berg2d0ddec2009-04-23 16:13:26 +02001599 struct ath_vif *avp = (void *)vif->drv_priv;
Felix Fietkau0005baf2010-01-15 02:33:40 +01001600 int slottime;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001601
Felix Fietkau96f372c2011-04-07 19:07:17 +02001602 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301603 mutex_lock(&sc->mutex);
1604
Rajkumar Manoharan9f619032012-03-10 05:06:49 +05301605 if (changed & BSS_CHANGED_ASSOC) {
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301606 ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n",
1607 bss_conf->bssid, bss_conf->assoc);
Sujithc6089cc2009-11-16 11:40:48 +05301608
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301609 if (avp->primary_sta_vif && !bss_conf->assoc) {
1610 clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags);
1611 avp->primary_sta_vif = false;
1612
1613 if (ah->opmode == NL80211_IFTYPE_STATION)
1614 clear_bit(SC_OP_BEACONS, &sc->sc_flags);
1615 }
1616
Johannes Berg8b2c9822012-11-06 20:23:30 +01001617 ieee80211_iterate_active_interfaces_atomic(
1618 sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
1619 ath9k_bss_assoc_iter, sc);
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301620
1621 if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) &&
1622 ah->opmode == NL80211_IFTYPE_STATION) {
1623 memset(common->curbssid, 0, ETH_ALEN);
1624 common->curaid = 0;
1625 ath9k_hw_write_associd(sc->sc_ah);
Rajkumar Manoharan50072eb2012-10-12 14:07:22 +05301626 if (ath9k_hw_mci_is_enabled(sc->sc_ah))
1627 ath9k_mci_update_wlan_channels(sc, true);
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301628 }
Johannes Berg2d0ddec2009-04-23 16:13:26 +02001629 }
1630
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301631 if (changed & BSS_CHANGED_IBSS) {
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301632 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1633 common->curaid = bss_conf->aid;
1634 ath9k_hw_write_associd(sc->sc_ah);
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301635 }
1636
Sujith Manoharanef4ad632012-07-17 17:15:56 +05301637 if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
1638 (changed & BSS_CHANGED_BEACON_INT)) {
Sujith Manoharan2f8e82e2012-07-17 17:16:16 +05301639 if (ah->opmode == NL80211_IFTYPE_AP &&
1640 bss_conf->enable_beacon)
1641 ath9k_set_tsfadjust(sc, vif);
Sujith Manoharanef4ad632012-07-17 17:15:56 +05301642 if (ath9k_allow_beacon_config(sc, vif))
1643 ath9k_beacon_config(sc, vif, changed);
Johannes Berg2d0ddec2009-04-23 16:13:26 +02001644 }
1645
Felix Fietkau0005baf2010-01-15 02:33:40 +01001646 if (changed & BSS_CHANGED_ERP_SLOT) {
1647 if (bss_conf->use_short_slot)
1648 slottime = 9;
1649 else
1650 slottime = 20;
1651 if (vif->type == NL80211_IFTYPE_AP) {
1652 /*
1653 * Defer update, so that connected stations can adjust
1654 * their settings at the same time.
1655 * See beacon.c for more details
1656 */
1657 sc->beacon.slottime = slottime;
1658 sc->beacon.updateslot = UPDATE;
1659 } else {
1660 ah->slottime = slottime;
1661 ath9k_hw_init_global_settings(ah);
1662 }
1663 }
1664
Sujith Manoharanda0d45f2012-07-17 17:16:29 +05301665 if (changed & CHECK_ANI)
1666 ath_check_ani(sc);
1667
Sujith141b38b2009-02-04 08:10:07 +05301668 mutex_unlock(&sc->mutex);
Felix Fietkau96f372c2011-04-07 19:07:17 +02001669 ath9k_ps_restore(sc);
Sujith Manoharanda0d45f2012-07-17 17:16:29 +05301670
1671#undef CHECK_ANI
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001672}
1673
Eliad Peller37a41b42011-09-21 14:06:11 +03001674static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001675{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001676 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001677 u64 tsf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001678
Sujith141b38b2009-02-04 08:10:07 +05301679 mutex_lock(&sc->mutex);
Sujith Manoharan9abbfb22010-12-10 11:27:06 +05301680 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301681 tsf = ath9k_hw_gettsf64(sc->sc_ah);
Sujith Manoharan9abbfb22010-12-10 11:27:06 +05301682 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301683 mutex_unlock(&sc->mutex);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001684
1685 return tsf;
1686}
1687
Eliad Peller37a41b42011-09-21 14:06:11 +03001688static void ath9k_set_tsf(struct ieee80211_hw *hw,
1689 struct ieee80211_vif *vif,
1690 u64 tsf)
Alina Friedrichsen3b5d6652009-01-24 07:09:59 +01001691{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001692 struct ath_softc *sc = hw->priv;
Alina Friedrichsen3b5d6652009-01-24 07:09:59 +01001693
Sujith141b38b2009-02-04 08:10:07 +05301694 mutex_lock(&sc->mutex);
Sujith Manoharan9abbfb22010-12-10 11:27:06 +05301695 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301696 ath9k_hw_settsf64(sc->sc_ah, tsf);
Sujith Manoharan9abbfb22010-12-10 11:27:06 +05301697 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301698 mutex_unlock(&sc->mutex);
Alina Friedrichsen3b5d6652009-01-24 07:09:59 +01001699}
1700
Eliad Peller37a41b42011-09-21 14:06:11 +03001701static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001702{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001703 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001704
Sujith141b38b2009-02-04 08:10:07 +05301705 mutex_lock(&sc->mutex);
Luis R. Rodriguez21526d52009-09-09 20:05:39 -07001706
1707 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301708 ath9k_hw_reset_tsf(sc->sc_ah);
Luis R. Rodriguez21526d52009-09-09 20:05:39 -07001709 ath9k_ps_restore(sc);
1710
Sujith141b38b2009-02-04 08:10:07 +05301711 mutex_unlock(&sc->mutex);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001712}
1713
1714static int ath9k_ampdu_action(struct ieee80211_hw *hw,
Johannes Bergc951ad32009-11-16 12:00:38 +01001715 struct ieee80211_vif *vif,
Sujith141b38b2009-02-04 08:10:07 +05301716 enum ieee80211_ampdu_mlme_action action,
1717 struct ieee80211_sta *sta,
Johannes Berg0b01f032011-01-18 13:51:05 +01001718 u16 tid, u16 *ssn, u8 buf_size)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001719{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001720 struct ath_softc *sc = hw->priv;
Felix Fietkau16e23422013-05-17 12:58:24 +02001721 bool flush = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001722 int ret = 0;
1723
Sujith Manoharan7ca7c772013-05-08 05:03:32 +05301724 mutex_lock(&sc->mutex);
Johannes Berg85ad1812010-06-10 10:21:49 +02001725
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001726 switch (action) {
1727 case IEEE80211_AMPDU_RX_START:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001728 break;
1729 case IEEE80211_AMPDU_RX_STOP:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001730 break;
1731 case IEEE80211_AMPDU_TX_START:
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001732 ath9k_ps_wakeup(sc);
Felix Fietkau231c3a12010-09-20 19:35:28 +02001733 ret = ath_tx_aggr_start(sc, sta, tid, ssn);
1734 if (!ret)
1735 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001736 ath9k_ps_restore(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001737 break;
Johannes Berg18b559d2012-07-18 13:51:25 +02001738 case IEEE80211_AMPDU_TX_STOP_FLUSH:
1739 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
Felix Fietkau16e23422013-05-17 12:58:24 +02001740 flush = true;
1741 case IEEE80211_AMPDU_TX_STOP_CONT:
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001742 ath9k_ps_wakeup(sc);
Sujithf83da962009-07-23 15:32:37 +05301743 ath_tx_aggr_stop(sc, sta, tid);
Felix Fietkau08c96ab2013-05-18 21:28:15 +02001744 if (!flush)
Felix Fietkau16e23422013-05-17 12:58:24 +02001745 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001746 ath9k_ps_restore(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001747 break;
Johannes Bergb1720232009-03-23 17:28:39 +01001748 case IEEE80211_AMPDU_TX_OPERATIONAL:
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001749 ath9k_ps_wakeup(sc);
Sujith8469cde2008-10-29 10:19:28 +05301750 ath_tx_aggr_resume(sc, sta, tid);
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001751 ath9k_ps_restore(sc);
Sujith8469cde2008-10-29 10:19:28 +05301752 break;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001753 default:
Joe Perches38002762010-12-02 19:12:36 -08001754 ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001755 }
1756
Sujith Manoharan7ca7c772013-05-08 05:03:32 +05301757 mutex_unlock(&sc->mutex);
Johannes Berg85ad1812010-06-10 10:21:49 +02001758
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001759 return ret;
1760}
1761
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001762static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
1763 struct survey_info *survey)
1764{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001765 struct ath_softc *sc = hw->priv;
Felix Fietkau34300982010-10-10 18:21:52 +02001766 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau39162db2010-09-29 19:12:06 +02001767 struct ieee80211_supported_band *sband;
Felix Fietkau34300982010-10-10 18:21:52 +02001768 struct ieee80211_channel *chan;
1769 unsigned long flags;
1770 int pos;
1771
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001772 if (config_enabled(CONFIG_ATH9K_TX99))
1773 return -EOPNOTSUPP;
1774
Felix Fietkau34300982010-10-10 18:21:52 +02001775 spin_lock_irqsave(&common->cc_lock, flags);
1776 if (idx == 0)
1777 ath_update_survey_stats(sc);
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001778
Felix Fietkau39162db2010-09-29 19:12:06 +02001779 sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ];
1780 if (sband && idx >= sband->n_channels) {
1781 idx -= sband->n_channels;
1782 sband = NULL;
1783 }
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001784
Felix Fietkau39162db2010-09-29 19:12:06 +02001785 if (!sband)
1786 sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ];
1787
Felix Fietkau34300982010-10-10 18:21:52 +02001788 if (!sband || idx >= sband->n_channels) {
1789 spin_unlock_irqrestore(&common->cc_lock, flags);
1790 return -ENOENT;
Felix Fietkau4f1a5a42010-09-29 17:15:28 +02001791 }
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001792
Felix Fietkau34300982010-10-10 18:21:52 +02001793 chan = &sband->channels[idx];
1794 pos = chan->hw_value;
1795 memcpy(survey, &sc->survey[pos], sizeof(*survey));
1796 survey->channel = chan;
1797 spin_unlock_irqrestore(&common->cc_lock, flags);
1798
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001799 return 0;
1800}
1801
Felix Fietkaue239d852010-01-15 02:34:58 +01001802static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
1803{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001804 struct ath_softc *sc = hw->priv;
Felix Fietkaue239d852010-01-15 02:34:58 +01001805 struct ath_hw *ah = sc->sc_ah;
1806
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001807 if (config_enabled(CONFIG_ATH9K_TX99))
1808 return;
1809
Felix Fietkaue239d852010-01-15 02:34:58 +01001810 mutex_lock(&sc->mutex);
1811 ah->coverage_class = coverage_class;
Mohammed Shafi Shajakhan8b2a38272011-08-24 21:38:07 +05301812
1813 ath9k_ps_wakeup(sc);
Felix Fietkaue239d852010-01-15 02:34:58 +01001814 ath9k_hw_init_global_settings(ah);
Mohammed Shafi Shajakhan8b2a38272011-08-24 21:38:07 +05301815 ath9k_ps_restore(sc);
1816
Felix Fietkaue239d852010-01-15 02:34:58 +01001817 mutex_unlock(&sc->mutex);
1818}
1819
Johannes Berg39ecc012013-02-13 12:11:00 +01001820static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001821{
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001822 struct ath_softc *sc = hw->priv;
Mohammed Shafi Shajakhan99aa55b2011-05-06 20:43:11 +05301823 struct ath_hw *ah = sc->sc_ah;
1824 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkau86271e42011-03-11 21:38:19 +01001825 int timeout = 200; /* ms */
1826 int i, j;
Rajkumar Manoharan2f6fc352011-04-28 15:31:57 +05301827 bool drain_txq;
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001828
1829 mutex_lock(&sc->mutex);
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001830 cancel_delayed_work_sync(&sc->tx_complete_work);
1831
Mohammed Shafi Shajakhan6a6b3f32011-09-09 10:41:08 +05301832 if (ah->ah_flags & AH_UNPLUGGED) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001833 ath_dbg(common, ANY, "Device has been unplugged!\n");
Mohammed Shafi Shajakhan6a6b3f32011-09-09 10:41:08 +05301834 mutex_unlock(&sc->mutex);
1835 return;
1836 }
1837
Sujith Manoharan781b14a2012-06-04 20:23:55 +05301838 if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001839 ath_dbg(common, ANY, "Device not present\n");
Mohammed Shafi Shajakhan99aa55b2011-05-06 20:43:11 +05301840 mutex_unlock(&sc->mutex);
1841 return;
1842 }
1843
Felix Fietkau86271e42011-03-11 21:38:19 +01001844 for (j = 0; j < timeout; j++) {
Mohammed Shafi Shajakhan108697c2011-05-13 20:59:42 +05301845 bool npend = false;
Felix Fietkau86271e42011-03-11 21:38:19 +01001846
1847 if (j)
1848 usleep_range(1000, 2000);
1849
1850 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1851 if (!ATH_TXQ_SETUP(sc, i))
1852 continue;
1853
Mohammed Shafi Shajakhan108697c2011-05-13 20:59:42 +05301854 npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
1855
1856 if (npend)
1857 break;
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001858 }
1859
Felix Fietkau86271e42011-03-11 21:38:19 +01001860 if (!npend)
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01001861 break;
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001862 }
1863
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01001864 if (drop) {
1865 ath9k_ps_wakeup(sc);
1866 spin_lock_bh(&sc->sc_pcu_lock);
Felix Fietkau13815592013-01-20 18:51:53 +01001867 drain_txq = ath_drain_all_txq(sc);
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01001868 spin_unlock_bh(&sc->sc_pcu_lock);
Felix Fietkau9adcf442011-09-03 01:40:26 +02001869
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01001870 if (!drain_txq)
Felix Fietkau13815592013-01-20 18:51:53 +01001871 ath_reset(sc);
Felix Fietkau9adcf442011-09-03 01:40:26 +02001872
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01001873 ath9k_ps_restore(sc);
1874 ieee80211_wake_queues(hw);
1875 }
Senthil Balasubramaniand78f4b32011-03-23 23:07:22 +05301876
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001877 ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
1878 mutex_unlock(&sc->mutex);
1879}
1880
Vivek Natarajan15b91e82011-04-06 11:41:11 +05301881static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
1882{
1883 struct ath_softc *sc = hw->priv;
1884 int i;
1885
1886 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1887 if (!ATH_TXQ_SETUP(sc, i))
1888 continue;
1889
1890 if (ath9k_has_pending_frames(sc, &sc->tx.txq[i]))
1891 return true;
1892 }
1893 return false;
1894}
1895
Mohammed Shafi Shajakhan5595f112011-05-19 18:08:57 +05301896static int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
Felix Fietkauba4903f2011-05-17 21:09:54 +02001897{
1898 struct ath_softc *sc = hw->priv;
1899 struct ath_hw *ah = sc->sc_ah;
1900 struct ieee80211_vif *vif;
1901 struct ath_vif *avp;
1902 struct ath_buf *bf;
1903 struct ath_tx_status ts;
Felix Fietkau4286df62012-02-27 19:58:40 +01001904 bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
Felix Fietkauba4903f2011-05-17 21:09:54 +02001905 int status;
1906
1907 vif = sc->beacon.bslot[0];
1908 if (!vif)
1909 return 0;
1910
Sujith Manoharanaa45fe92012-07-17 17:16:03 +05301911 if (!vif->bss_conf.enable_beacon)
Felix Fietkauba4903f2011-05-17 21:09:54 +02001912 return 0;
1913
Sujith Manoharanaa45fe92012-07-17 17:16:03 +05301914 avp = (void *)vif->drv_priv;
1915
Felix Fietkau4286df62012-02-27 19:58:40 +01001916 if (!sc->beacon.tx_processed && !edma) {
Felix Fietkauba4903f2011-05-17 21:09:54 +02001917 tasklet_disable(&sc->bcon_tasklet);
1918
1919 bf = avp->av_bcbuf;
1920 if (!bf || !bf->bf_mpdu)
1921 goto skip;
1922
1923 status = ath9k_hw_txprocdesc(ah, bf->bf_desc, &ts);
1924 if (status == -EINPROGRESS)
1925 goto skip;
1926
1927 sc->beacon.tx_processed = true;
1928 sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
1929
1930skip:
1931 tasklet_enable(&sc->bcon_tasklet);
1932 }
1933
1934 return sc->beacon.tx_last;
1935}
1936
Mohammed Shafi Shajakhan52c94f42011-08-20 17:21:42 +05301937static int ath9k_get_stats(struct ieee80211_hw *hw,
1938 struct ieee80211_low_level_stats *stats)
1939{
1940 struct ath_softc *sc = hw->priv;
1941 struct ath_hw *ah = sc->sc_ah;
1942 struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats;
1943
1944 stats->dot11ACKFailureCount = mib_stats->ackrcv_bad;
1945 stats->dot11RTSFailureCount = mib_stats->rts_bad;
1946 stats->dot11FCSErrorCount = mib_stats->fcs_bad;
1947 stats->dot11RTSSuccessCount = mib_stats->rts_good;
1948 return 0;
1949}
1950
Felix Fietkau43c35282011-09-03 01:40:27 +02001951static u32 fill_chainmask(u32 cap, u32 new)
1952{
1953 u32 filled = 0;
1954 int i;
1955
1956 for (i = 0; cap && new; i++, cap >>= 1) {
1957 if (!(cap & BIT(0)))
1958 continue;
1959
1960 if (new & BIT(0))
1961 filled |= BIT(i);
1962
1963 new >>= 1;
1964 }
1965
1966 return filled;
1967}
1968
Felix Fietkau5d9c7e32012-07-15 19:53:30 +02001969static bool validate_antenna_mask(struct ath_hw *ah, u32 val)
1970{
Felix Fietkaufea92cb2013-01-20 21:55:22 +01001971 if (AR_SREV_9300_20_OR_LATER(ah))
1972 return true;
1973
Felix Fietkau5d9c7e32012-07-15 19:53:30 +02001974 switch (val & 0x7) {
1975 case 0x1:
1976 case 0x3:
1977 case 0x7:
1978 return true;
1979 case 0x2:
1980 return (ah->caps.rx_chainmask == 1);
1981 default:
1982 return false;
1983 }
1984}
1985
Felix Fietkau43c35282011-09-03 01:40:27 +02001986static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
1987{
1988 struct ath_softc *sc = hw->priv;
1989 struct ath_hw *ah = sc->sc_ah;
1990
Felix Fietkau5d9c7e32012-07-15 19:53:30 +02001991 if (ah->caps.rx_chainmask != 1)
1992 rx_ant |= tx_ant;
1993
1994 if (!validate_antenna_mask(ah, rx_ant) || !tx_ant)
Felix Fietkau43c35282011-09-03 01:40:27 +02001995 return -EINVAL;
1996
1997 sc->ant_rx = rx_ant;
1998 sc->ant_tx = tx_ant;
1999
2000 if (ah->caps.rx_chainmask == 1)
2001 return 0;
2002
2003 /* AR9100 runs into calibration issues if not all rx chains are enabled */
2004 if (AR_SREV_9100(ah))
2005 ah->rxchainmask = 0x7;
2006 else
2007 ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);
2008
2009 ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant);
2010 ath9k_reload_chainmask_settings(sc);
2011
2012 return 0;
2013}
2014
2015static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
2016{
2017 struct ath_softc *sc = hw->priv;
2018
2019 *tx_ant = sc->ant_tx;
2020 *rx_ant = sc->ant_rx;
2021 return 0;
2022}
2023
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302024#ifdef CONFIG_PM_SLEEP
2025
2026static void ath9k_wow_map_triggers(struct ath_softc *sc,
2027 struct cfg80211_wowlan *wowlan,
2028 u32 *wow_triggers)
2029{
2030 if (wowlan->disconnect)
2031 *wow_triggers |= AH_WOW_LINK_CHANGE |
2032 AH_WOW_BEACON_MISS;
2033 if (wowlan->magic_pkt)
2034 *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
2035
2036 if (wowlan->n_patterns)
2037 *wow_triggers |= AH_WOW_USER_PATTERN_EN;
2038
2039 sc->wow_enabled = *wow_triggers;
2040
2041}
2042
2043static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
2044{
2045 struct ath_hw *ah = sc->sc_ah;
2046 struct ath_common *common = ath9k_hw_common(ah);
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302047 int pattern_count = 0;
2048 int i, byte_cnt;
2049 u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
2050 u8 dis_deauth_mask[MAX_PATTERN_SIZE];
2051
2052 memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE);
2053 memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE);
2054
2055 /*
2056 * Create Dissassociate / Deauthenticate packet filter
2057 *
2058 * 2 bytes 2 byte 6 bytes 6 bytes 6 bytes
2059 * +--------------+----------+---------+--------+--------+----
2060 * + Frame Control+ Duration + DA + SA + BSSID +
2061 * +--------------+----------+---------+--------+--------+----
2062 *
2063 * The above is the management frame format for disassociate/
2064 * deauthenticate pattern, from this we need to match the first byte
2065 * of 'Frame Control' and DA, SA, and BSSID fields
2066 * (skipping 2nd byte of FC and Duration feild.
2067 *
2068 * Disassociate pattern
2069 * --------------------
2070 * Frame control = 00 00 1010
2071 * DA, SA, BSSID = x:x:x:x:x:x
2072 * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x
2073 * | x:x:x:x:x:x -- 22 bytes
2074 *
2075 * Deauthenticate pattern
2076 * ----------------------
2077 * Frame control = 00 00 1100
2078 * DA, SA, BSSID = x:x:x:x:x:x
2079 * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x
2080 * | x:x:x:x:x:x -- 22 bytes
2081 */
2082
2083 /* Create Disassociate Pattern first */
2084
2085 byte_cnt = 0;
2086
2087 /* Fill out the mask with all FF's */
2088
2089 for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++)
2090 dis_deauth_mask[i] = 0xff;
2091
2092 /* copy the first byte of frame control field */
2093 dis_deauth_pattern[byte_cnt] = 0xa0;
2094 byte_cnt++;
2095
2096 /* skip 2nd byte of frame control and Duration field */
2097 byte_cnt += 3;
2098
2099 /*
2100 * need not match the destination mac address, it can be a broadcast
2101 * mac address or an unicast to this station
2102 */
2103 byte_cnt += 6;
2104
2105 /* copy the source mac address */
2106 memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
2107
2108 byte_cnt += 6;
2109
2110 /* copy the bssid, its same as the source mac address */
2111
2112 memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
2113
2114 /* Create Disassociate pattern mask */
2115
Sujith Manoharan846e4382013-06-03 09:19:24 +05302116 dis_deauth_mask[0] = 0xfe;
2117 dis_deauth_mask[1] = 0x03;
2118 dis_deauth_mask[2] = 0xc0;
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302119
2120 ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");
2121
2122 ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
2123 pattern_count, byte_cnt);
2124
2125 pattern_count++;
2126 /*
2127 * for de-authenticate pattern, only the first byte of the frame
2128 * control field gets changed from 0xA0 to 0xC0
2129 */
2130 dis_deauth_pattern[0] = 0xC0;
2131
2132 ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
2133 pattern_count, byte_cnt);
2134
2135}
2136
2137static void ath9k_wow_add_pattern(struct ath_softc *sc,
2138 struct cfg80211_wowlan *wowlan)
2139{
2140 struct ath_hw *ah = sc->sc_ah;
2141 struct ath9k_wow_pattern *wow_pattern = NULL;
Amitkumar Karwar50ac6602013-06-25 19:03:56 -07002142 struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302143 int mask_len;
2144 s8 i = 0;
2145
2146 if (!wowlan->n_patterns)
2147 return;
2148
2149 /*
2150 * Add the new user configured patterns
2151 */
2152 for (i = 0; i < wowlan->n_patterns; i++) {
2153
2154 wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL);
2155
2156 if (!wow_pattern)
2157 return;
2158
2159 /*
2160 * TODO: convert the generic user space pattern to
2161 * appropriate chip specific/802.11 pattern.
2162 */
2163
2164 mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
2165 memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE);
2166 memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE);
2167 memcpy(wow_pattern->pattern_bytes, patterns[i].pattern,
2168 patterns[i].pattern_len);
2169 memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len);
2170 wow_pattern->pattern_len = patterns[i].pattern_len;
2171
2172 /*
2173 * just need to take care of deauth and disssoc pattern,
2174 * make sure we don't overwrite them.
2175 */
2176
2177 ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes,
2178 wow_pattern->mask_bytes,
2179 i + 2,
2180 wow_pattern->pattern_len);
2181 kfree(wow_pattern);
2182
2183 }
2184
2185}
2186
2187static int ath9k_suspend(struct ieee80211_hw *hw,
2188 struct cfg80211_wowlan *wowlan)
2189{
2190 struct ath_softc *sc = hw->priv;
2191 struct ath_hw *ah = sc->sc_ah;
2192 struct ath_common *common = ath9k_hw_common(ah);
2193 u32 wow_triggers_enabled = 0;
2194 int ret = 0;
2195
2196 mutex_lock(&sc->mutex);
2197
2198 ath_cancel_work(sc);
Mohammed Shafi Shajakhan5686cac2012-09-04 19:33:34 +05302199 ath_stop_ani(sc);
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302200 del_timer_sync(&sc->rx_poll_timer);
2201
2202 if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
2203 ath_dbg(common, ANY, "Device not present\n");
2204 ret = -EINVAL;
2205 goto fail_wow;
2206 }
2207
2208 if (WARN_ON(!wowlan)) {
2209 ath_dbg(common, WOW, "None of the WoW triggers enabled\n");
2210 ret = -EINVAL;
2211 goto fail_wow;
2212 }
2213
2214 if (!device_can_wakeup(sc->dev)) {
2215 ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n");
2216 ret = 1;
2217 goto fail_wow;
2218 }
2219
2220 /*
2221 * none of the sta vifs are associated
2222 * and we are not currently handling multivif
2223 * cases, for instance we have to seperately
2224 * configure 'keep alive frame' for each
2225 * STA.
2226 */
2227
2228 if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
2229 ath_dbg(common, WOW, "None of the STA vifs are associated\n");
2230 ret = 1;
2231 goto fail_wow;
2232 }
2233
2234 if (sc->nvifs > 1) {
2235 ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
2236 ret = 1;
2237 goto fail_wow;
2238 }
2239
2240 ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled);
2241
2242 ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n",
2243 wow_triggers_enabled);
2244
2245 ath9k_ps_wakeup(sc);
2246
2247 ath9k_stop_btcoex(sc);
2248
2249 /*
2250 * Enable wake up on recieving disassoc/deauth
2251 * frame by default.
2252 */
2253 ath9k_wow_add_disassoc_deauth_pattern(sc);
2254
2255 if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN)
2256 ath9k_wow_add_pattern(sc, wowlan);
2257
2258 spin_lock_bh(&sc->sc_pcu_lock);
2259 /*
2260 * To avoid false wake, we enable beacon miss interrupt only
2261 * when we go to sleep. We save the current interrupt mask
2262 * so we can restore it after the system wakes up
2263 */
2264 sc->wow_intr_before_sleep = ah->imask;
2265 ah->imask &= ~ATH9K_INT_GLOBAL;
2266 ath9k_hw_disable_interrupts(ah);
2267 ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL;
2268 ath9k_hw_set_interrupts(ah);
2269 ath9k_hw_enable_interrupts(ah);
2270
2271 spin_unlock_bh(&sc->sc_pcu_lock);
2272
2273 /*
2274 * we can now sync irq and kill any running tasklets, since we already
2275 * disabled interrupts and not holding a spin lock
2276 */
2277 synchronize_irq(sc->irq);
2278 tasklet_kill(&sc->intr_tq);
2279
2280 ath9k_hw_wow_enable(ah, wow_triggers_enabled);
2281
2282 ath9k_ps_restore(sc);
2283 ath_dbg(common, ANY, "WoW enabled in ath9k\n");
2284 atomic_inc(&sc->wow_sleep_proc_intr);
2285
2286fail_wow:
2287 mutex_unlock(&sc->mutex);
2288 return ret;
2289}
2290
2291static int ath9k_resume(struct ieee80211_hw *hw)
2292{
2293 struct ath_softc *sc = hw->priv;
2294 struct ath_hw *ah = sc->sc_ah;
2295 struct ath_common *common = ath9k_hw_common(ah);
2296 u32 wow_status;
2297
2298 mutex_lock(&sc->mutex);
2299
2300 ath9k_ps_wakeup(sc);
2301
2302 spin_lock_bh(&sc->sc_pcu_lock);
2303
2304 ath9k_hw_disable_interrupts(ah);
2305 ah->imask = sc->wow_intr_before_sleep;
2306 ath9k_hw_set_interrupts(ah);
2307 ath9k_hw_enable_interrupts(ah);
2308
2309 spin_unlock_bh(&sc->sc_pcu_lock);
2310
2311 wow_status = ath9k_hw_wow_wakeup(ah);
2312
2313 if (atomic_read(&sc->wow_got_bmiss_intr) == 0) {
2314 /*
2315 * some devices may not pick beacon miss
2316 * as the reason they woke up so we add
2317 * that here for that shortcoming.
2318 */
2319 wow_status |= AH_WOW_BEACON_MISS;
2320 atomic_dec(&sc->wow_got_bmiss_intr);
2321 ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n");
2322 }
2323
2324 atomic_dec(&sc->wow_sleep_proc_intr);
2325
2326 if (wow_status) {
2327 ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n",
2328 ath9k_hw_wow_event_to_string(wow_status), wow_status);
2329 }
2330
2331 ath_restart_work(sc);
2332 ath9k_start_btcoex(sc);
2333
2334 ath9k_ps_restore(sc);
2335 mutex_unlock(&sc->mutex);
2336
2337 return 0;
2338}
2339
2340static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
2341{
2342 struct ath_softc *sc = hw->priv;
2343
2344 mutex_lock(&sc->mutex);
2345 device_init_wakeup(sc->dev, 1);
2346 device_set_wakeup_enable(sc->dev, enabled);
2347 mutex_unlock(&sc->mutex);
2348}
2349
2350#endif
Simon Wunderliche93d0832013-01-08 14:48:58 +01002351static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
2352{
2353 struct ath_softc *sc = hw->priv;
Sujith Manoharan73900cb2013-05-08 05:03:31 +05302354 set_bit(SC_OP_SCANNING, &sc->sc_flags);
Simon Wunderliche93d0832013-01-08 14:48:58 +01002355}
2356
2357static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
2358{
2359 struct ath_softc *sc = hw->priv;
Sujith Manoharan73900cb2013-05-08 05:03:31 +05302360 clear_bit(SC_OP_SCANNING, &sc->sc_flags);
Simon Wunderliche93d0832013-01-08 14:48:58 +01002361}
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302362
Simon Wunderlichd074e8d2013-08-14 08:01:38 +02002363static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw,
2364 struct ieee80211_vif *vif,
2365 struct cfg80211_chan_def *chandef)
2366{
2367 struct ath_softc *sc = hw->priv;
2368
2369 /* mac80211 does not support CSA in multi-if cases (yet) */
2370 if (WARN_ON(sc->csa_vif))
2371 return;
2372
2373 sc->csa_vif = vif;
2374}
2375
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07002376static void ath9k_tx99_stop(struct ath_softc *sc)
2377{
2378 struct ath_hw *ah = sc->sc_ah;
2379 struct ath_common *common = ath9k_hw_common(ah);
2380
2381 ath_drain_all_txq(sc);
2382 ath_startrecv(sc);
2383
2384 ath9k_hw_set_interrupts(ah);
2385 ath9k_hw_enable_interrupts(ah);
2386
2387 ieee80211_wake_queues(sc->hw);
2388
2389 kfree_skb(sc->tx99_skb);
2390 sc->tx99_skb = NULL;
2391 sc->tx99_state = false;
2392
2393 ath9k_hw_tx99_stop(sc->sc_ah);
2394 ath_dbg(common, XMIT, "TX99 stopped\n");
2395}
2396
2397static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
2398{
2399 static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24,
2400 0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50,
2401 0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1,
2402 0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18,
2403 0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8,
2404 0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84,
2405 0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,
2406 0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};
2407 u32 len = 1200;
2408 struct ieee80211_hw *hw = sc->hw;
2409 struct ieee80211_hdr *hdr;
2410 struct ieee80211_tx_info *tx_info;
2411 struct sk_buff *skb;
2412
2413 skb = alloc_skb(len, GFP_KERNEL);
2414 if (!skb)
2415 return NULL;
2416
2417 skb_put(skb, len);
2418
2419 memset(skb->data, 0, len);
2420
2421 hdr = (struct ieee80211_hdr *)skb->data;
2422 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA);
2423 hdr->duration_id = 0;
2424
2425 memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);
2426 memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
2427 memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
2428
2429 hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
2430
2431 tx_info = IEEE80211_SKB_CB(skb);
2432 memset(tx_info, 0, sizeof(*tx_info));
2433 tx_info->band = hw->conf.chandef.chan->band;
2434 tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
2435 tx_info->control.vif = sc->tx99_vif;
2436
2437 memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data));
2438
2439 return skb;
2440}
2441
2442void ath9k_tx99_deinit(struct ath_softc *sc)
2443{
2444 ath_reset(sc);
2445
2446 ath9k_ps_wakeup(sc);
2447 ath9k_tx99_stop(sc);
2448 ath9k_ps_restore(sc);
2449}
2450
2451int ath9k_tx99_init(struct ath_softc *sc)
2452{
2453 struct ieee80211_hw *hw = sc->hw;
2454 struct ath_hw *ah = sc->sc_ah;
2455 struct ath_common *common = ath9k_hw_common(ah);
2456 struct ath_tx_control txctl;
2457 int r;
2458
2459 if (sc->sc_flags & SC_OP_INVALID) {
2460 ath_err(common,
2461 "driver is in invalid state unable to use TX99");
2462 return -EINVAL;
2463 }
2464
2465 sc->tx99_skb = ath9k_build_tx99_skb(sc);
2466 if (!sc->tx99_skb)
2467 return -ENOMEM;
2468
2469 memset(&txctl, 0, sizeof(txctl));
2470 txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
2471
2472 ath_reset(sc);
2473
2474 ath9k_ps_wakeup(sc);
2475
2476 ath9k_hw_disable_interrupts(ah);
2477 atomic_set(&ah->intr_ref_cnt, -1);
2478 ath_drain_all_txq(sc);
2479 ath_stoprecv(sc);
2480
2481 sc->tx99_state = true;
2482
2483 ieee80211_stop_queues(hw);
2484
2485 if (sc->tx99_power == MAX_RATE_POWER + 1)
2486 sc->tx99_power = MAX_RATE_POWER;
2487
2488 ath9k_hw_tx99_set_txpower(ah, sc->tx99_power);
2489 r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl);
2490 if (r) {
2491 ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n");
2492 return r;
2493 }
2494
2495 ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n",
2496 sc->tx99_power,
2497 sc->tx99_power / 2);
2498
2499 /* We leave the harware awake as it will be chugging on */
2500
2501 return 0;
2502}
2503
Gabor Juhos6baff7f2009-01-14 20:17:06 +01002504struct ieee80211_ops ath9k_ops = {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002505 .tx = ath9k_tx,
2506 .start = ath9k_start,
2507 .stop = ath9k_stop,
2508 .add_interface = ath9k_add_interface,
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05302509 .change_interface = ath9k_change_interface,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002510 .remove_interface = ath9k_remove_interface,
2511 .config = ath9k_config,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002512 .configure_filter = ath9k_configure_filter,
Johannes Berg4ca77862010-02-19 19:06:56 +01002513 .sta_add = ath9k_sta_add,
2514 .sta_remove = ath9k_sta_remove,
Felix Fietkau55195412011-04-17 23:28:09 +02002515 .sta_notify = ath9k_sta_notify,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002516 .conf_tx = ath9k_conf_tx,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002517 .bss_info_changed = ath9k_bss_info_changed,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002518 .set_key = ath9k_set_key,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002519 .get_tsf = ath9k_get_tsf,
Alina Friedrichsen3b5d6652009-01-24 07:09:59 +01002520 .set_tsf = ath9k_set_tsf,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002521 .reset_tsf = ath9k_reset_tsf,
Johannes Berg4233df62008-10-13 13:35:05 +02002522 .ampdu_action = ath9k_ampdu_action,
Benoit Papillault62dad5b2010-04-28 00:08:24 +02002523 .get_survey = ath9k_get_survey,
Johannes Berg3b319aa2009-06-13 14:50:26 +05302524 .rfkill_poll = ath9k_rfkill_poll_state,
Felix Fietkaue239d852010-01-15 02:34:58 +01002525 .set_coverage_class = ath9k_set_coverage_class,
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08002526 .flush = ath9k_flush,
Vivek Natarajan15b91e82011-04-06 11:41:11 +05302527 .tx_frames_pending = ath9k_tx_frames_pending,
Mohammed Shafi Shajakhan52c94f42011-08-20 17:21:42 +05302528 .tx_last_beacon = ath9k_tx_last_beacon,
Felix Fietkau86a22ac2013-06-07 18:12:01 +02002529 .release_buffered_frames = ath9k_release_buffered_frames,
Mohammed Shafi Shajakhan52c94f42011-08-20 17:21:42 +05302530 .get_stats = ath9k_get_stats,
Felix Fietkau43c35282011-09-03 01:40:27 +02002531 .set_antenna = ath9k_set_antenna,
2532 .get_antenna = ath9k_get_antenna,
Ben Greearb90bd9d2012-05-15 15:33:25 -07002533
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302534#ifdef CONFIG_PM_SLEEP
2535 .suspend = ath9k_suspend,
2536 .resume = ath9k_resume,
2537 .set_wakeup = ath9k_set_wakeup,
2538#endif
2539
Ben Greearb90bd9d2012-05-15 15:33:25 -07002540#ifdef CONFIG_ATH9K_DEBUGFS
2541 .get_et_sset_count = ath9k_get_et_sset_count,
Sujith Manoharana145daf2012-11-28 15:08:54 +05302542 .get_et_stats = ath9k_get_et_stats,
2543 .get_et_strings = ath9k_get_et_strings,
2544#endif
2545
2546#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
2547 .sta_add_debugfs = ath9k_sta_add_debugfs,
Ben Greearb90bd9d2012-05-15 15:33:25 -07002548#endif
Simon Wunderliche93d0832013-01-08 14:48:58 +01002549 .sw_scan_start = ath9k_sw_scan_start,
2550 .sw_scan_complete = ath9k_sw_scan_complete,
Simon Wunderlichd074e8d2013-08-14 08:01:38 +02002551 .channel_switch_beacon = ath9k_channel_switch_beacon,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002552};