blob: b200e11e44fb2ca556c004d20d6388ba68d516f4 [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
Sven Eckelmann313eb872012-06-25 07:15:22 +020022u8 ath9k_parse_mpdudensity(u8 mpdudensity)
Sujithff37e332008-11-24 12:07:55 +053023{
24 /*
25 * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
26 * 0 for no restriction
27 * 1 for 1/4 us
28 * 2 for 1/2 us
29 * 3 for 1 us
30 * 4 for 2 us
31 * 5 for 4 us
32 * 6 for 8 us
33 * 7 for 16 us
34 */
35 switch (mpdudensity) {
36 case 0:
37 return 0;
38 case 1:
39 case 2:
40 case 3:
41 /* Our lower layer calculations limit our precision to
42 1 microsecond */
43 return 1;
44 case 4:
45 return 2;
46 case 5:
47 return 4;
48 case 6:
49 return 8;
50 case 7:
51 return 16;
52 default:
53 return 0;
54 }
55}
56
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -080057static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq)
58{
59 bool pending = false;
60
61 spin_lock_bh(&txq->axq_lock);
62
Sujith Manoharanb7367282014-10-02 06:33:13 +053063 if (txq->axq_depth) {
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -080064 pending = true;
Sujith Manoharanb7367282014-10-02 06:33:13 +053065 goto out;
66 }
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -080067
Felix Fietkau04535312014-06-11 16:17:51 +053068 if (txq->mac80211_qnum >= 0) {
69 struct list_head *list;
70
71 list = &sc->cur_chan->acq[txq->mac80211_qnum];
72 if (!list_empty(list))
73 pending = true;
74 }
Sujith Manoharanb7367282014-10-02 06:33:13 +053075out:
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -080076 spin_unlock_bh(&txq->axq_lock);
77 return pending;
78}
79
Mohammed Shafi Shajakhan6d79cb42011-05-19 17:40:46 +053080static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
Luis R. Rodriguez8c77a562009-09-09 21:02:34 -070081{
82 unsigned long flags;
83 bool ret;
84
Luis R. Rodriguez9ecdef42009-09-09 21:10:09 -070085 spin_lock_irqsave(&sc->sc_pm_lock, flags);
86 ret = ath9k_hw_setpower(sc->sc_ah, mode);
87 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
Luis R. Rodriguez8c77a562009-09-09 21:02:34 -070088
89 return ret;
90}
91
Felix Fietkaubf3dac52013-11-11 22:23:33 +010092void ath_ps_full_sleep(unsigned long data)
93{
94 struct ath_softc *sc = (struct ath_softc *) data;
95 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
96 bool reset;
97
98 spin_lock(&common->cc_lock);
99 ath_hw_cycle_counters_update(common);
100 spin_unlock(&common->cc_lock);
101
102 ath9k_hw_setrxabort(sc->sc_ah, 1);
103 ath9k_hw_stopdmarecv(sc->sc_ah, &reset);
104
105 ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
106}
107
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -0700108void ath9k_ps_wakeup(struct ath_softc *sc)
109{
Felix Fietkau898c9142010-10-12 14:02:53 +0200110 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -0700111 unsigned long flags;
Felix Fietkaufbb078f2010-11-03 01:36:51 +0100112 enum ath9k_power_mode power_mode;
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -0700113
114 spin_lock_irqsave(&sc->sc_pm_lock, flags);
115 if (++sc->ps_usecount != 1)
116 goto unlock;
117
Felix Fietkaubf3dac52013-11-11 22:23:33 +0100118 del_timer_sync(&sc->sleep_timer);
Felix Fietkaufbb078f2010-11-03 01:36:51 +0100119 power_mode = sc->sc_ah->power_mode;
Luis R. Rodriguez9ecdef42009-09-09 21:10:09 -0700120 ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -0700121
Felix Fietkau898c9142010-10-12 14:02:53 +0200122 /*
123 * While the hardware is asleep, the cycle counters contain no
124 * useful data. Better clear them now so that they don't mess up
125 * survey data results.
126 */
Felix Fietkaufbb078f2010-11-03 01:36:51 +0100127 if (power_mode != ATH9K_PM_AWAKE) {
128 spin_lock(&common->cc_lock);
129 ath_hw_cycle_counters_update(common);
130 memset(&common->cc_survey, 0, sizeof(common->cc_survey));
Rajkumar Manoharanc9ae6ab2012-06-04 16:28:41 +0530131 memset(&common->cc_ani, 0, sizeof(common->cc_ani));
Felix Fietkaufbb078f2010-11-03 01:36:51 +0100132 spin_unlock(&common->cc_lock);
133 }
Felix Fietkau898c9142010-10-12 14:02:53 +0200134
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -0700135 unlock:
136 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
137}
138
139void ath9k_ps_restore(struct ath_softc *sc)
140{
Felix Fietkau898c9142010-10-12 14:02:53 +0200141 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkauc6c539f2011-09-14 21:24:24 +0200142 enum ath9k_power_mode mode;
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -0700143 unsigned long flags;
144
145 spin_lock_irqsave(&sc->sc_pm_lock, flags);
146 if (--sc->ps_usecount != 0)
147 goto unlock;
148
Sujith Manoharanad128862012-04-24 10:23:20 +0530149 if (sc->ps_idle) {
Felix Fietkaubf3dac52013-11-11 22:23:33 +0100150 mod_timer(&sc->sleep_timer, jiffies + HZ / 10);
151 goto unlock;
152 }
153
154 if (sc->ps_enabled &&
Sujith Manoharanad128862012-04-24 10:23:20 +0530155 !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
156 PS_WAIT_FOR_CAB |
157 PS_WAIT_FOR_PSPOLL_DATA |
Rajkumar Manoharan424749c2012-10-10 23:03:02 +0530158 PS_WAIT_FOR_TX_ACK |
159 PS_WAIT_FOR_ANI))) {
Felix Fietkauc6c539f2011-09-14 21:24:24 +0200160 mode = ATH9K_PM_NETWORK_SLEEP;
Rajkumar Manoharan08d4df42012-07-01 19:53:54 +0530161 if (ath9k_hw_btcoex_is_enabled(sc->sc_ah))
162 ath9k_btcoex_stop_gen_timer(sc);
Sujith Manoharanad128862012-04-24 10:23:20 +0530163 } else {
Felix Fietkauc6c539f2011-09-14 21:24:24 +0200164 goto unlock;
Sujith Manoharanad128862012-04-24 10:23:20 +0530165 }
Felix Fietkauc6c539f2011-09-14 21:24:24 +0200166
167 spin_lock(&common->cc_lock);
168 ath_hw_cycle_counters_update(common);
169 spin_unlock(&common->cc_lock);
170
Felix Fietkau1a8f0d392011-09-22 08:04:32 -0600171 ath9k_hw_setpower(sc->sc_ah, mode);
Luis R. Rodrigueza91d75ae2009-09-09 20:29:18 -0700172
173 unlock:
174 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
175}
176
Felix Fietkau9adcf442011-09-03 01:40:26 +0200177static void __ath_cancel_work(struct ath_softc *sc)
178{
179 cancel_work_sync(&sc->paprd_work);
Felix Fietkau9adcf442011-09-03 01:40:26 +0200180 cancel_delayed_work_sync(&sc->tx_complete_work);
181 cancel_delayed_work_sync(&sc->hw_pll_work);
Sujith Manoharanfad29cd2012-06-25 13:54:22 +0530182
Sujith Manoharanbf525922012-06-27 14:15:59 +0530183#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
Sujith Manoharanfad29cd2012-06-25 13:54:22 +0530184 if (ath9k_hw_mci_is_enabled(sc->sc_ah))
185 cancel_work_sync(&sc->mci_work);
Sujith Manoharanbf525922012-06-27 14:15:59 +0530186#endif
Felix Fietkau9adcf442011-09-03 01:40:26 +0200187}
188
Sujith Manoharane60001e2013-10-28 12:22:04 +0530189void ath_cancel_work(struct ath_softc *sc)
Felix Fietkau9adcf442011-09-03 01:40:26 +0200190{
191 __ath_cancel_work(sc);
192 cancel_work_sync(&sc->hw_reset_work);
193}
194
Sujith Manoharane60001e2013-10-28 12:22:04 +0530195void ath_restart_work(struct ath_softc *sc)
Sujith Manoharanaf68aba2012-06-04 20:23:43 +0530196{
Sujith Manoharanaf68aba2012-06-04 20:23:43 +0530197 ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
198
Sujith Manoharan19c36162013-08-20 10:05:59 +0530199 if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9330(sc->sc_ah))
Sujith Manoharanaf68aba2012-06-04 20:23:43 +0530200 ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
201 msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
202
Sujith Manoharanda0d45f2012-07-17 17:16:29 +0530203 ath_start_ani(sc);
Sujith Manoharanaf68aba2012-06-04 20:23:43 +0530204}
205
John W. Linville9ebea382013-01-28 13:54:03 -0500206static bool ath_prepare_reset(struct ath_softc *sc)
Felix Fietkau9adcf442011-09-03 01:40:26 +0200207{
208 struct ath_hw *ah = sc->sc_ah;
Felix Fietkauceea2a52012-05-24 14:32:19 +0200209 bool ret = true;
Felix Fietkau9adcf442011-09-03 01:40:26 +0200210
211 ieee80211_stop_queues(sc->hw);
Sujith Manoharanda0d45f2012-07-17 17:16:29 +0530212 ath_stop_ani(sc);
Felix Fietkau9adcf442011-09-03 01:40:26 +0200213 ath9k_hw_disable_interrupts(ah);
214
Felix Fietkau13815592013-01-20 18:51:53 +0100215 if (!ath_drain_all_txq(sc))
Felix Fietkau9adcf442011-09-03 01:40:26 +0200216 ret = false;
217
Felix Fietkau0a62acb2013-01-20 18:51:52 +0100218 if (!ath_stoprecv(sc))
Felix Fietkauceea2a52012-05-24 14:32:19 +0200219 ret = false;
220
Felix Fietkau9adcf442011-09-03 01:40:26 +0200221 return ret;
222}
223
224static bool ath_complete_reset(struct ath_softc *sc, bool start)
225{
226 struct ath_hw *ah = sc->sc_ah;
227 struct ath_common *common = ath9k_hw_common(ah);
Sujith Manoharan196fb862012-06-04 20:24:13 +0530228 unsigned long flags;
Felix Fietkau9adcf442011-09-03 01:40:26 +0200229
Sujith Manoharan9019f642014-09-05 08:03:15 +0530230 ath9k_calculate_summary_state(sc, sc->cur_chan);
Sujith Manoharan19ec4772014-09-05 08:03:16 +0530231 ath_startrecv(sc);
Felix Fietkau9adcf442011-09-03 01:40:26 +0200232 ath9k_cmn_update_txpow(ah, sc->curtxpow,
Felix Fietkaubc7e1be2014-06-11 16:17:50 +0530233 sc->cur_chan->txpower, &sc->curtxpow);
Oleksij Rempeleefa01d2014-02-27 11:40:46 +0100234 clear_bit(ATH_OP_HW_RESET, &common->op_flags);
Felix Fietkau9adcf442011-09-03 01:40:26 +0200235
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530236 if (!sc->cur_chan->offchannel && start) {
Felix Fietkau8d7e09d2014-06-11 16:18:01 +0530237 /* restore per chanctx TSF timer */
238 if (sc->cur_chan->tsf_val) {
239 u32 offset;
240
241 offset = ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts,
242 NULL);
243 ath9k_hw_settsf64(ah, sc->cur_chan->tsf_val + offset);
244 }
245
246
Oleksij Rempeleefa01d2014-02-27 11:40:46 +0100247 if (!test_bit(ATH_OP_BEACONS, &common->op_flags))
Sujith Manoharan196fb862012-06-04 20:24:13 +0530248 goto work;
Felix Fietkau9adcf442011-09-03 01:40:26 +0200249
Sujith Manoharan196fb862012-06-04 20:24:13 +0530250 if (ah->opmode == NL80211_IFTYPE_STATION &&
Oleksij Rempeleefa01d2014-02-27 11:40:46 +0100251 test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {
Sujith Manoharan196fb862012-06-04 20:24:13 +0530252 spin_lock_irqsave(&sc->sc_pm_lock, flags);
253 sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
254 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
Sujith Manoharana6768282013-05-06 10:09:03 +0530255 } else {
256 ath9k_set_beacon(sc);
Sujith Manoharan196fb862012-06-04 20:24:13 +0530257 }
258 work:
Sujith Manoharanaf68aba2012-06-04 20:23:43 +0530259 ath_restart_work(sc);
Felix Fietkau04535312014-06-11 16:17:51 +0530260 ath_txq_schedule_all(sc);
Felix Fietkau9adcf442011-09-03 01:40:26 +0200261 }
262
Sujith Manoharan071aa9a2014-01-13 13:55:11 +0530263 sc->gtt_cnt = 0;
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +0530264
265 ath9k_hw_set_interrupts(ah);
266 ath9k_hw_enable_interrupts(ah);
267
Sujith Manoharan499afac2014-08-22 20:39:31 +0530268 if (!ath9k_is_chanctx_enabled())
Rajkumar Manoharan3ad9c382014-06-11 16:18:15 +0530269 ieee80211_wake_queues(sc->hw);
Sujith Manoharan0e08b5f2014-08-23 13:29:19 +0530270 else
271 ath9k_chanctx_wake_queues(sc);
Felix Fietkau9adcf442011-09-03 01:40:26 +0200272
Felix Fietkaud463af42014-04-06 00:37:03 +0200273 ath9k_p2p_ps_timer(sc);
274
Felix Fietkau9adcf442011-09-03 01:40:26 +0200275 return true;
276}
277
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530278int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
Felix Fietkau9adcf442011-09-03 01:40:26 +0200279{
280 struct ath_hw *ah = sc->sc_ah;
281 struct ath_common *common = ath9k_hw_common(ah);
282 struct ath9k_hw_cal_data *caldata = NULL;
283 bool fastcc = true;
Felix Fietkau9adcf442011-09-03 01:40:26 +0200284 int r;
285
286 __ath_cancel_work(sc);
287
Felix Fietkau4668cce2013-01-14 16:56:46 +0100288 tasklet_disable(&sc->intr_tq);
Felix Fietkau9adcf442011-09-03 01:40:26 +0200289 spin_lock_bh(&sc->sc_pcu_lock);
290
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530291 if (!sc->cur_chan->offchannel) {
Felix Fietkau9adcf442011-09-03 01:40:26 +0200292 fastcc = false;
Felix Fietkaub01459e2014-06-11 16:17:59 +0530293 caldata = &sc->cur_chan->caldata;
Felix Fietkau9adcf442011-09-03 01:40:26 +0200294 }
295
296 if (!hchan) {
297 fastcc = false;
Felix Fietkau9adcf442011-09-03 01:40:26 +0200298 hchan = ah->curchan;
299 }
300
John W. Linville9ebea382013-01-28 13:54:03 -0500301 if (!ath_prepare_reset(sc))
Felix Fietkau9adcf442011-09-03 01:40:26 +0200302 fastcc = false;
303
Sujith Manoharan9ea35982014-08-27 12:07:23 +0530304 if (ath9k_is_chanctx_enabled())
305 fastcc = false;
306
Rajkumar Manoharand6067f02014-06-20 22:47:49 +0530307 spin_lock_bh(&sc->chan_lock);
308 sc->cur_chandef = sc->cur_chan->chandef;
309 spin_unlock_bh(&sc->chan_lock);
Felix Fietkaubff11762014-06-11 16:17:52 +0530310
Joe Perchesd2182b62011-12-15 14:55:53 -0800311 ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n",
Sujith Manoharanfeced202012-01-30 14:21:42 +0530312 hchan->channel, IS_CHAN_HT40(hchan), fastcc);
Felix Fietkau9adcf442011-09-03 01:40:26 +0200313
314 r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
315 if (r) {
316 ath_err(common,
317 "Unable to reset channel, reset status %d\n", r);
Robert Shadef50b1cd2013-04-02 19:52:45 -0400318
319 ath9k_hw_enable_interrupts(ah);
320 ath9k_queue_reset(sc, RESET_TYPE_BB_HANG);
321
Felix Fietkau9adcf442011-09-03 01:40:26 +0200322 goto out;
323 }
324
Rajkumar Manoharane82cb032012-10-12 14:07:25 +0530325 if (ath9k_hw_mci_is_enabled(sc->sc_ah) &&
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530326 sc->cur_chan->offchannel)
Rajkumar Manoharane82cb032012-10-12 14:07:25 +0530327 ath9k_mci_set_txpower(sc, true, false);
328
Felix Fietkau9adcf442011-09-03 01:40:26 +0200329 if (!ath_complete_reset(sc, true))
330 r = -EIO;
331
332out:
333 spin_unlock_bh(&sc->sc_pcu_lock);
Felix Fietkau4668cce2013-01-14 16:56:46 +0100334 tasklet_enable(&sc->intr_tq);
335
Felix Fietkau9adcf442011-09-03 01:40:26 +0200336 return r;
337}
338
Ben Greear7e1e3862011-11-03 11:33:13 -0700339static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
340 struct ieee80211_vif *vif)
Sujithff37e332008-11-24 12:07:55 +0530341{
342 struct ath_node *an;
Sujithff37e332008-11-24 12:07:55 +0530343 an = (struct ath_node *)sta->drv_priv;
344
Sujith Manoharana145daf2012-11-28 15:08:54 +0530345 an->sc = sc;
Ben Greear7f010c92011-01-09 23:11:49 -0800346 an->sta = sta;
Ben Greear7e1e3862011-11-03 11:33:13 -0700347 an->vif = vif;
Rajkumar Manoharan4bbf4412014-05-22 12:35:49 +0530348 memset(&an->key_idx, 0, sizeof(an->key_idx));
Sujith Manoharan3d4e20f2012-03-14 14:40:58 +0530349
Sujith Manoharandd5ee592013-02-04 15:38:23 +0530350 ath_tx_node_init(sc, an);
Lorenzo Bianconi44b47a72014-09-16 02:13:16 +0200351
352 ath_dynack_node_init(sc->sc_ah, an);
Sujithff37e332008-11-24 12:07:55 +0530353}
354
355static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
356{
357 struct ath_node *an = (struct ath_node *)sta->drv_priv;
Sujith Manoharandd5ee592013-02-04 15:38:23 +0530358 ath_tx_node_cleanup(sc, an);
Lorenzo Bianconi44b47a72014-09-16 02:13:16 +0200359
360 ath_dynack_node_deinit(sc->sc_ah, an);
Sujithff37e332008-11-24 12:07:55 +0530361}
362
Sujith55624202010-01-08 10:36:02 +0530363void ath9k_tasklet(unsigned long data)
Sujithff37e332008-11-24 12:07:55 +0530364{
365 struct ath_softc *sc = (struct ath_softc *)data;
Luis R. Rodriguezaf03abe2009-09-09 02:33:11 -0700366 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700367 struct ath_common *common = ath9k_hw_common(ah);
Rajkumar Manoharan124b9792012-07-17 17:16:42 +0530368 enum ath_reset_type type;
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530369 unsigned long flags;
Sujith17d79042009-02-09 13:27:03 +0530370 u32 status = sc->intrstatus;
Felix Fietkaub5c804752010-04-15 17:38:48 -0400371 u32 rxmask;
Sujithff37e332008-11-24 12:07:55 +0530372
Felix Fietkaue3927002011-09-14 21:23:01 +0200373 ath9k_ps_wakeup(sc);
374 spin_lock(&sc->sc_pcu_lock);
375
Sujith Manoharan6549a862013-12-24 10:44:24 +0530376 if (status & ATH9K_INT_FATAL) {
377 type = RESET_TYPE_FATAL_INT;
Rajkumar Manoharan124b9792012-07-17 17:16:42 +0530378 ath9k_queue_reset(sc, type);
Sujith Manoharanc6cc47b2013-09-16 10:37:00 +0530379
380 /*
381 * Increment the ref. counter here so that
382 * interrupts are enabled in the reset routine.
383 */
384 atomic_inc(&ah->intr_ref_cnt);
Felix Fietkauaffad452014-02-22 14:52:49 +0100385 ath_dbg(common, RESET, "FATAL: Skipping interrupts\n");
Felix Fietkaue3927002011-09-14 21:23:01 +0200386 goto out;
Sujithff37e332008-11-24 12:07:55 +0530387 }
388
Sujith Manoharan6549a862013-12-24 10:44:24 +0530389 if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) &&
390 (status & ATH9K_INT_BB_WATCHDOG)) {
Sujith Manoharan0c759972013-12-24 10:44:26 +0530391 spin_lock(&common->cc_lock);
392 ath_hw_cycle_counters_update(common);
393 ar9003_hw_bb_watchdog_dbg_info(ah);
394 spin_unlock(&common->cc_lock);
395
Sujith Manoharan6549a862013-12-24 10:44:24 +0530396 if (ar9003_hw_bb_watchdog_check(ah)) {
397 type = RESET_TYPE_BB_WATCHDOG;
398 ath9k_queue_reset(sc, type);
399
400 /*
401 * Increment the ref. counter here so that
402 * interrupts are enabled in the reset routine.
403 */
404 atomic_inc(&ah->intr_ref_cnt);
Felix Fietkauaffad452014-02-22 14:52:49 +0100405 ath_dbg(common, RESET,
Sujith Manoharan6549a862013-12-24 10:44:24 +0530406 "BB_WATCHDOG: Skipping interrupts\n");
407 goto out;
408 }
409 }
410
Sujith Manoharan071aa9a2014-01-13 13:55:11 +0530411 if (status & ATH9K_INT_GTT) {
412 sc->gtt_cnt++;
413
414 if ((sc->gtt_cnt >= MAX_GTT_CNT) && !ath9k_hw_check_alive(ah)) {
415 type = RESET_TYPE_TX_GTT;
416 ath9k_queue_reset(sc, type);
417 atomic_inc(&ah->intr_ref_cnt);
Felix Fietkauaffad452014-02-22 14:52:49 +0100418 ath_dbg(common, RESET,
Sujith Manoharan071aa9a2014-01-13 13:55:11 +0530419 "GTT: Skipping interrupts\n");
420 goto out;
421 }
422 }
423
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530424 spin_lock_irqsave(&sc->sc_pm_lock, flags);
Rajkumar Manoharan4105f802011-05-06 18:27:47 +0530425 if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
426 /*
427 * TSF sync does not look correct; remain awake to sync with
428 * the next Beacon.
429 */
Joe Perchesd2182b62011-12-15 14:55:53 -0800430 ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n");
Rajkumar Manoharane8fe7332011-08-05 18:59:41 +0530431 sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
Rajkumar Manoharan4105f802011-05-06 18:27:47 +0530432 }
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530433 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
Rajkumar Manoharan4105f802011-05-06 18:27:47 +0530434
Felix Fietkaub5c804752010-04-15 17:38:48 -0400435 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
436 rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
437 ATH9K_INT_RXORN);
438 else
439 rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
440
441 if (status & rxmask) {
Felix Fietkaub5c804752010-04-15 17:38:48 -0400442 /* Check for high priority Rx first */
443 if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
444 (status & ATH9K_INT_RXHP))
445 ath_rx_tasklet(sc, 0, true);
446
447 ath_rx_tasklet(sc, 0, false);
Sujith063d8be2009-03-30 15:28:49 +0530448 }
449
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400450 if (status & ATH9K_INT_TX) {
Sujith Manoharan071aa9a2014-01-13 13:55:11 +0530451 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
452 /*
453 * For EDMA chips, TX completion is enabled for the
454 * beacon queue, so if a beacon has been transmitted
455 * successfully after a GTT interrupt, the GTT counter
456 * gets reset to zero here.
457 */
Sujith Manoharan3b745c72014-01-20 13:25:28 +0530458 sc->gtt_cnt = 0;
Sujith Manoharan071aa9a2014-01-13 13:55:11 +0530459
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400460 ath_tx_edma_tasklet(sc);
Sujith Manoharan071aa9a2014-01-13 13:55:11 +0530461 } else {
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400462 ath_tx_tasklet(sc);
Sujith Manoharan071aa9a2014-01-13 13:55:11 +0530463 }
Felix Fietkau10e23182013-11-11 22:23:35 +0100464
465 wake_up(&sc->tx_wait);
Vasanthakumar Thiagarajane5003242010-04-15 17:39:36 -0400466 }
Sujith063d8be2009-03-30 15:28:49 +0530467
Felix Fietkauc67ce332013-12-14 18:03:38 +0100468 if (status & ATH9K_INT_GENTIMER)
469 ath_gen_timer_isr(sc->sc_ah);
470
Sujith Manoharan56ca0db2012-02-22 12:40:32 +0530471 ath9k_btcoex_handle_interrupt(sc, status);
Mohammed Shafi Shajakhan19686dd2011-11-30 10:41:28 +0530472
Sujithff37e332008-11-24 12:07:55 +0530473 /* re-enable hardware interrupt */
Felix Fietkau4df30712010-11-08 20:54:47 +0100474 ath9k_hw_enable_interrupts(ah);
Sujith Manoharanc6cc47b2013-09-16 10:37:00 +0530475out:
Senthil Balasubramanian52671e42010-12-23 21:06:57 +0530476 spin_unlock(&sc->sc_pcu_lock);
Vasanthakumar Thiagarajan153e0802009-05-15 02:47:16 -0400477 ath9k_ps_restore(sc);
Sujithff37e332008-11-24 12:07:55 +0530478}
479
Gabor Juhos6baff7f2009-01-14 20:17:06 +0100480irqreturn_t ath_isr(int irq, void *dev)
Sujithff37e332008-11-24 12:07:55 +0530481{
Sujith063d8be2009-03-30 15:28:49 +0530482#define SCHED_INTR ( \
483 ATH9K_INT_FATAL | \
Rajkumar Manoharana4d86d92011-05-20 17:52:10 +0530484 ATH9K_INT_BB_WATCHDOG | \
Sujith063d8be2009-03-30 15:28:49 +0530485 ATH9K_INT_RXORN | \
486 ATH9K_INT_RXEOL | \
487 ATH9K_INT_RX | \
Felix Fietkaub5c804752010-04-15 17:38:48 -0400488 ATH9K_INT_RXLP | \
489 ATH9K_INT_RXHP | \
Sujith063d8be2009-03-30 15:28:49 +0530490 ATH9K_INT_TX | \
491 ATH9K_INT_BMISS | \
492 ATH9K_INT_CST | \
Sujith Manoharan071aa9a2014-01-13 13:55:11 +0530493 ATH9K_INT_GTT | \
Vasanthakumar Thiagarajanebb8e1d2009-09-01 17:46:32 +0530494 ATH9K_INT_TSFOOR | \
Mohammed Shafi Shajakhan40dc5392011-11-30 10:41:18 +0530495 ATH9K_INT_GENTIMER | \
496 ATH9K_INT_MCI)
Sujith063d8be2009-03-30 15:28:49 +0530497
Sujithff37e332008-11-24 12:07:55 +0530498 struct ath_softc *sc = dev;
Sujithcbe61d82009-02-09 13:27:12 +0530499 struct ath_hw *ah = sc->sc_ah;
Oleksij Rempeleefa01d2014-02-27 11:40:46 +0100500 struct ath_common *common = ath9k_hw_common(ah);
Sujithff37e332008-11-24 12:07:55 +0530501 enum ath9k_int status;
Sujith Manoharan78c8a952013-12-28 09:47:15 +0530502 u32 sync_cause = 0;
Sujithff37e332008-11-24 12:07:55 +0530503 bool sched = false;
504
Sujith063d8be2009-03-30 15:28:49 +0530505 /*
506 * The hardware is not ready/present, don't
507 * touch anything. Note this can happen early
508 * on if the IRQ is shared.
509 */
Oleksij Rempeleefa01d2014-02-27 11:40:46 +0100510 if (test_bit(ATH_OP_INVALID, &common->op_flags))
Sujith063d8be2009-03-30 15:28:49 +0530511 return IRQ_NONE;
Sujithff37e332008-11-24 12:07:55 +0530512
Sujith063d8be2009-03-30 15:28:49 +0530513 /* shared irq, not for us */
Sujithff37e332008-11-24 12:07:55 +0530514
Vasanthakumar Thiagarajan153e0802009-05-15 02:47:16 -0400515 if (!ath9k_hw_intrpend(ah))
Sujith063d8be2009-03-30 15:28:49 +0530516 return IRQ_NONE;
Sujithff37e332008-11-24 12:07:55 +0530517
Oleksij Rempeleefa01d2014-02-27 11:40:46 +0100518 if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
Felix Fietkauf41a9b32012-08-08 16:25:03 +0200519 ath9k_hw_kill_interrupts(ah);
Sujith Manoharanb74713d2012-06-04 20:24:01 +0530520 return IRQ_HANDLED;
Felix Fietkauf41a9b32012-08-08 16:25:03 +0200521 }
Sujith Manoharanb74713d2012-06-04 20:24:01 +0530522
Sujith063d8be2009-03-30 15:28:49 +0530523 /*
524 * Figure out the reason(s) for the interrupt. Note
525 * that the hal returns a pseudo-ISR that may include
526 * bits we haven't explicitly enabled so we mask the
527 * value to insure we only process bits we requested.
528 */
Felix Fietkau6a4d05d2013-12-19 18:01:48 +0100529 ath9k_hw_getisr(ah, &status, &sync_cause); /* NB: clears ISR too */
530 ath9k_debug_sync_cause(sc, sync_cause);
Pavel Roskin30691682010-03-31 18:05:31 -0400531 status &= ah->imask; /* discard unasked-for bits */
Sujith063d8be2009-03-30 15:28:49 +0530532
533 /*
534 * If there are no status bits set, then this interrupt was not
535 * for me (should have been caught above).
536 */
Vasanthakumar Thiagarajan153e0802009-05-15 02:47:16 -0400537 if (!status)
Sujith063d8be2009-03-30 15:28:49 +0530538 return IRQ_NONE;
Sujith063d8be2009-03-30 15:28:49 +0530539
540 /* Cache the status */
541 sc->intrstatus = status;
542
543 if (status & SCHED_INTR)
544 sched = true;
545
546 /*
547 * If a FATAL or RXORN interrupt is received, we have to reset the
548 * chip immediately.
549 */
Felix Fietkaub5c804752010-04-15 17:38:48 -0400550 if ((status & ATH9K_INT_FATAL) || ((status & ATH9K_INT_RXORN) &&
551 !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)))
Sujith063d8be2009-03-30 15:28:49 +0530552 goto chip_reset;
553
Sujith Manoharana6bb8602013-12-24 10:44:22 +0530554 if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) &&
Sujith Manoharan0c759972013-12-24 10:44:26 +0530555 (status & ATH9K_INT_BB_WATCHDOG))
Luis R. Rodriguez08578b82010-05-13 13:33:44 -0400556 goto chip_reset;
Sujith Manoharane60001e2013-10-28 12:22:04 +0530557
558#ifdef CONFIG_ATH9K_WOW
Rajkumar Manoharanca90ef42012-11-20 18:29:59 +0530559 if (status & ATH9K_INT_BMISS) {
560 if (atomic_read(&sc->wow_sleep_proc_intr) == 0) {
Rajkumar Manoharanca90ef42012-11-20 18:29:59 +0530561 atomic_inc(&sc->wow_got_bmiss_intr);
562 atomic_dec(&sc->wow_sleep_proc_intr);
563 }
564 }
565#endif
Sujith Manoharane60001e2013-10-28 12:22:04 +0530566
Sujith063d8be2009-03-30 15:28:49 +0530567 if (status & ATH9K_INT_SWBA)
568 tasklet_schedule(&sc->bcon_tasklet);
569
570 if (status & ATH9K_INT_TXURN)
571 ath9k_hw_updatetxtriglevel(ah, true);
572
Rajkumar Manoharan0682c9b2011-08-13 10:28:09 +0530573 if (status & ATH9K_INT_RXEOL) {
574 ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
Felix Fietkau72d874c2011-10-08 20:06:19 +0200575 ath9k_hw_set_interrupts(ah);
Felix Fietkaub5c804752010-04-15 17:38:48 -0400576 }
577
Vasanthakumar Thiagarajan153e0802009-05-15 02:47:16 -0400578 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
579 if (status & ATH9K_INT_TIM_TIMER) {
Luis R. Rodriguezff9f0b62010-12-07 15:13:22 -0800580 if (ATH_DBG_WARN_ON_ONCE(sc->ps_idle))
581 goto chip_reset;
Sujith063d8be2009-03-30 15:28:49 +0530582 /* Clear RxAbort bit so that we can
583 * receive frames */
Luis R. Rodriguez9ecdef42009-09-09 21:10:09 -0700584 ath9k_setpower(sc, ATH9K_PM_AWAKE);
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530585 spin_lock(&sc->sc_pm_lock);
Vasanthakumar Thiagarajan153e0802009-05-15 02:47:16 -0400586 ath9k_hw_setrxabort(sc->sc_ah, 0);
Sujith1b04b932010-01-08 10:36:05 +0530587 sc->ps_flags |= PS_WAIT_FOR_BEACON;
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530588 spin_unlock(&sc->sc_pm_lock);
Sujith063d8be2009-03-30 15:28:49 +0530589 }
Sujith063d8be2009-03-30 15:28:49 +0530590
591chip_reset:
592
Sujith817e11d2008-12-07 21:42:44 +0530593 ath_debug_stat_interrupt(sc, status);
594
Sujithff37e332008-11-24 12:07:55 +0530595 if (sched) {
Felix Fietkau4df30712010-11-08 20:54:47 +0100596 /* turn off every interrupt */
597 ath9k_hw_disable_interrupts(ah);
Sujithff37e332008-11-24 12:07:55 +0530598 tasklet_schedule(&sc->intr_tq);
599 }
600
601 return IRQ_HANDLED;
Sujith063d8be2009-03-30 15:28:49 +0530602
603#undef SCHED_INTR
Sujithff37e332008-11-24 12:07:55 +0530604}
605
Sujith Manoharanef6b19e2013-10-24 12:04:39 +0530606int ath_reset(struct ath_softc *sc)
Sujithff37e332008-11-24 12:07:55 +0530607{
Felix Fietkauec303262013-10-05 14:09:30 +0200608 int r;
Sujithff37e332008-11-24 12:07:55 +0530609
Felix Fietkau783cd012011-01-21 18:52:38 +0100610 ath9k_ps_wakeup(sc);
Felix Fietkau13815592013-01-20 18:51:53 +0100611 r = ath_reset_internal(sc, NULL);
Felix Fietkau783cd012011-01-21 18:52:38 +0100612 ath9k_ps_restore(sc);
Sujith2ab81d42009-12-14 16:34:56 +0530613
Luis R. Rodriguezae8d2852008-12-23 15:58:40 -0800614 return r;
Sujithff37e332008-11-24 12:07:55 +0530615}
616
Rajkumar Manoharan124b9792012-07-17 17:16:42 +0530617void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
618{
Oleksij Rempeleefa01d2014-02-27 11:40:46 +0100619 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Rajkumar Manoharan124b9792012-07-17 17:16:42 +0530620#ifdef CONFIG_ATH9K_DEBUGFS
621 RESET_STAT_INC(sc, type);
622#endif
Oleksij Rempeleefa01d2014-02-27 11:40:46 +0100623 set_bit(ATH_OP_HW_RESET, &common->op_flags);
Rajkumar Manoharan124b9792012-07-17 17:16:42 +0530624 ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
625}
626
Felix Fietkau236de512011-09-03 01:40:25 +0200627void ath_reset_work(struct work_struct *work)
628{
629 struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
630
Felix Fietkau13815592013-01-20 18:51:53 +0100631 ath_reset(sc);
Felix Fietkau236de512011-09-03 01:40:25 +0200632}
633
Sujithff37e332008-11-24 12:07:55 +0530634/**********************/
635/* mac80211 callbacks */
636/**********************/
637
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700638static int ath9k_start(struct ieee80211_hw *hw)
639{
Felix Fietkau9ac586152011-01-24 19:23:18 +0100640 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezaf03abe2009-09-09 02:33:11 -0700641 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700642 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkau39305632014-06-11 16:17:57 +0530643 struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan;
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530644 struct ath_chanctx *ctx = sc->cur_chan;
Sujithff37e332008-11-24 12:07:55 +0530645 struct ath9k_channel *init_channel;
Vasanthakumar Thiagarajan82880a72009-06-13 14:50:24 +0530646 int r;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700647
Joe Perchesd2182b62011-12-15 14:55:53 -0800648 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -0800649 "Starting driver with initial channel: %d MHz\n",
650 curchan->center_freq);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700651
Felix Fietkauf62d8162011-03-25 17:43:41 +0100652 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +0530653 mutex_lock(&sc->mutex);
654
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530655 init_channel = ath9k_cmn_get_channel(hw, ah, &ctx->chandef);
Felix Fietkaubff11762014-06-11 16:17:52 +0530656 sc->cur_chandef = hw->conf.chandef;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700657
Sujithff37e332008-11-24 12:07:55 +0530658 /* Reset SERDES registers */
Stanislaw Gruszka84c87dc2011-08-05 13:10:32 +0200659 ath9k_hw_configpcipowersave(ah, false);
Sujithff37e332008-11-24 12:07:55 +0530660
661 /*
662 * The basic interface to setting the hardware in a good
663 * state is ``reset''. On return the hardware is known to
664 * be powered up and with interrupts disabled. This must
665 * be followed by initialization of the appropriate bits
666 * and then setup of the interrupt mask.
667 */
Luis R. Rodriguez4bdd1e92010-10-26 15:27:24 -0700668 spin_lock_bh(&sc->sc_pcu_lock);
Felix Fietkauc0c11742011-11-16 13:08:41 +0100669
670 atomic_set(&ah->intr_ref_cnt, -1);
671
Felix Fietkau20bd2a02010-07-31 00:12:00 +0200672 r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
Luis R. Rodriguezae8d2852008-12-23 15:58:40 -0800673 if (r) {
Joe Perches38002762010-12-02 19:12:36 -0800674 ath_err(common,
675 "Unable to reset hardware; reset status %d (freq %u MHz)\n",
676 r, curchan->center_freq);
Felix Fietkauceb26a62012-10-03 21:07:51 +0200677 ah->reset_power_on = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700678 }
Sujithff37e332008-11-24 12:07:55 +0530679
Sujithff37e332008-11-24 12:07:55 +0530680 /* Setup our intr mask. */
Felix Fietkaub5c804752010-04-15 17:38:48 -0400681 ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
682 ATH9K_INT_RXORN | ATH9K_INT_FATAL |
683 ATH9K_INT_GLOBAL;
684
685 if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
Luis R. Rodriguez08578b82010-05-13 13:33:44 -0400686 ah->imask |= ATH9K_INT_RXHP |
Sujith Manoharana6bb8602013-12-24 10:44:22 +0530687 ATH9K_INT_RXLP;
Felix Fietkaub5c804752010-04-15 17:38:48 -0400688 else
689 ah->imask |= ATH9K_INT_RX;
Sujithff37e332008-11-24 12:07:55 +0530690
Sujith Manoharana6bb8602013-12-24 10:44:22 +0530691 if (ah->config.hw_hang_checks & HW_BB_WATCHDOG)
692 ah->imask |= ATH9K_INT_BB_WATCHDOG;
693
Sujith Manoharan071aa9a2014-01-13 13:55:11 +0530694 /*
695 * Enable GTT interrupts only for AR9003/AR9004 chips
696 * for now.
697 */
698 if (AR_SREV_9300_20_OR_LATER(ah))
699 ah->imask |= ATH9K_INT_GTT;
Sujithff37e332008-11-24 12:07:55 +0530700
Luis R. Rodriguezaf03abe2009-09-09 02:33:11 -0700701 if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
Pavel Roskin30691682010-03-31 18:05:31 -0400702 ah->imask |= ATH9K_INT_CST;
Sujithff37e332008-11-24 12:07:55 +0530703
Sujith Manoharane270e772012-06-04 16:27:19 +0530704 ath_mci_enable(sc);
Mohammed Shafi Shajakhan40dc5392011-11-30 10:41:18 +0530705
Oleksij Rempeleefa01d2014-02-27 11:40:46 +0100706 clear_bit(ATH_OP_INVALID, &common->op_flags);
Rajkumar Manoharan5f841b42010-10-27 18:31:15 +0530707 sc->sc_ah->is_monitoring = false;
Sujithff37e332008-11-24 12:07:55 +0530708
Felix Fietkauceb26a62012-10-03 21:07:51 +0200709 if (!ath_complete_reset(sc, false))
710 ah->reset_power_on = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700711
Felix Fietkauc0c11742011-11-16 13:08:41 +0100712 if (ah->led_pin >= 0) {
713 ath9k_hw_cfg_output(ah, ah->led_pin,
714 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
715 ath9k_hw_set_gpio(ah, ah->led_pin, 0);
716 }
717
718 /*
719 * Reset key cache to sane defaults (all entries cleared) instead of
720 * semi-random values after suspend/resume.
721 */
722 ath9k_cmn_init_crypto(sc->sc_ah);
723
Felix Fietkaua35051c2013-12-14 18:03:45 +0100724 ath9k_hw_reset_tsf(ah);
725
Felix Fietkau9adcf442011-09-03 01:40:26 +0200726 spin_unlock_bh(&sc->sc_pcu_lock);
Senthil Balasubramanian164ace32009-07-14 20:17:09 -0400727
Sujith141b38b2009-02-04 08:10:07 +0530728 mutex_unlock(&sc->mutex);
729
Felix Fietkauf62d8162011-03-25 17:43:41 +0100730 ath9k_ps_restore(sc);
731
Felix Fietkauceb26a62012-10-03 21:07:51 +0200732 return 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700733}
734
Thomas Huehn36323f82012-07-23 21:33:42 +0200735static void ath9k_tx(struct ieee80211_hw *hw,
736 struct ieee80211_tx_control *control,
737 struct sk_buff *skb)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700738{
Felix Fietkau9ac586152011-01-24 19:23:18 +0100739 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700740 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith528f0c62008-10-29 10:14:26 +0530741 struct ath_tx_control txctl;
Benoit Papillault1bc14882009-11-24 15:49:18 +0100742 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530743 unsigned long flags;
Sujith528f0c62008-10-29 10:14:26 +0530744
Gabor Juhos96148322009-07-24 17:27:21 +0200745 if (sc->ps_enabled) {
Jouni Malinendc8c4582009-05-19 17:01:42 +0300746 /*
747 * mac80211 does not set PM field for normal data frames, so we
748 * need to update that based on the current PS mode.
749 */
750 if (ieee80211_is_data(hdr->frame_control) &&
751 !ieee80211_is_nullfunc(hdr->frame_control) &&
752 !ieee80211_has_pm(hdr->frame_control)) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800753 ath_dbg(common, PS,
Joe Perches226afe62010-12-02 19:12:37 -0800754 "Add PM=1 for a TX frame while in PS mode\n");
Jouni Malinendc8c4582009-05-19 17:01:42 +0300755 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
756 }
757 }
758
Sujith Manoharanad128862012-04-24 10:23:20 +0530759 if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP)) {
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300760 /*
761 * We are using PS-Poll and mac80211 can request TX while in
762 * power save mode. Need to wake up hardware for the TX to be
763 * completed and if needed, also for RX of buffered frames.
764 */
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300765 ath9k_ps_wakeup(sc);
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530766 spin_lock_irqsave(&sc->sc_pm_lock, flags);
Vasanthakumar Thiagarajanfdf76622010-05-17 18:57:55 -0700767 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
768 ath9k_hw_setrxabort(sc->sc_ah, 0);
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300769 if (ieee80211_is_pspoll(hdr->frame_control)) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800770 ath_dbg(common, PS,
Joe Perches226afe62010-12-02 19:12:37 -0800771 "Sending PS-Poll to pick a buffered frame\n");
Sujith1b04b932010-01-08 10:36:05 +0530772 sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA;
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300773 } else {
Joe Perchesd2182b62011-12-15 14:55:53 -0800774 ath_dbg(common, PS, "Wake up to complete TX\n");
Sujith1b04b932010-01-08 10:36:05 +0530775 sc->ps_flags |= PS_WAIT_FOR_TX_ACK;
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300776 }
777 /*
778 * The actual restore operation will happen only after
Sujith Manoharanad128862012-04-24 10:23:20 +0530779 * the ps_flags bit is cleared. We are just dropping
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300780 * the ps_usecount here.
781 */
Sujith Manoharan07c15a32012-06-04 20:24:07 +0530782 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
Jouni Malinen9a23f9c2009-05-19 17:01:38 +0300783 ath9k_ps_restore(sc);
784 }
785
Sujith Manoharanad128862012-04-24 10:23:20 +0530786 /*
787 * Cannot tx while the hardware is in full sleep, it first needs a full
788 * chip reset to recover from that
789 */
790 if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP)) {
791 ath_err(common, "TX while HW is in FULL_SLEEP mode\n");
792 goto exit;
793 }
794
Sujith528f0c62008-10-29 10:14:26 +0530795 memset(&txctl, 0, sizeof(struct ath_tx_control));
Felix Fietkau066dae92010-11-07 14:59:39 +0100796 txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)];
Thomas Huehn36323f82012-07-23 21:33:42 +0200797 txctl.sta = control->sta;
Sujith528f0c62008-10-29 10:14:26 +0530798
Joe Perchesd2182b62011-12-15 14:55:53 -0800799 ath_dbg(common, XMIT, "transmitting packet, skb: %p\n", skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700800
Jouni Malinenc52f33d2009-03-03 19:23:29 +0200801 if (ath_tx_start(hw, skb, &txctl) != 0) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800802 ath_dbg(common, XMIT, "TX failed\n");
Ben Greeara5a0bca2012-04-03 09:16:55 -0700803 TX_STAT_INC(txctl.txq->axq_qnum, txfailed);
Sujith528f0c62008-10-29 10:14:26 +0530804 goto exit;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700805 }
806
Johannes Berg7bb45682011-02-24 14:42:06 +0100807 return;
Sujith528f0c62008-10-29 10:14:26 +0530808exit:
Felix Fietkau249ee722012-10-03 21:07:52 +0200809 ieee80211_free_txskb(hw, skb);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700810}
811
812static void ath9k_stop(struct ieee80211_hw *hw)
813{
Felix Fietkau9ac586152011-01-24 19:23:18 +0100814 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezaf03abe2009-09-09 02:33:11 -0700815 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700816 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkauc0c11742011-11-16 13:08:41 +0100817 bool prev_idle;
Sujith9c84b792008-10-29 10:17:13 +0530818
Sujith Manoharanea22df22014-08-23 13:29:07 +0530819 ath9k_deinit_channel_context(sc);
820
Sujith4c483812009-08-18 10:51:52 +0530821 mutex_lock(&sc->mutex);
822
Felix Fietkau9adcf442011-09-03 01:40:26 +0200823 ath_cancel_work(sc);
Luis R. Rodriguezc94dbff2009-07-27 11:53:04 -0700824
Oleksij Rempeleefa01d2014-02-27 11:40:46 +0100825 if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800826 ath_dbg(common, ANY, "Device not present\n");
Sujith4c483812009-08-18 10:51:52 +0530827 mutex_unlock(&sc->mutex);
Sujith9c84b792008-10-29 10:17:13 +0530828 return;
829 }
830
Sujith3867cf62009-12-23 20:03:27 -0500831 /* Ensure HW is awake when we try to shut it down. */
832 ath9k_ps_wakeup(sc);
833
Luis R. Rodriguez6a6733f2010-10-26 15:27:25 -0700834 spin_lock_bh(&sc->sc_pcu_lock);
835
Stanislaw Gruszka203043f2011-01-25 14:08:40 +0100836 /* prevent tasklets to enable interrupts once we disable them */
837 ah->imask &= ~ATH9K_INT_GLOBAL;
838
Sujithff37e332008-11-24 12:07:55 +0530839 /* make sure h/w will not generate any interrupt
840 * before setting the invalid flag. */
Felix Fietkau4df30712010-11-08 20:54:47 +0100841 ath9k_hw_disable_interrupts(ah);
Sujithff37e332008-11-24 12:07:55 +0530842
Luis R. Rodriguez6a6733f2010-10-26 15:27:25 -0700843 spin_unlock_bh(&sc->sc_pcu_lock);
844
Stanislaw Gruszka203043f2011-01-25 14:08:40 +0100845 /* we can now sync irq and kill any running tasklets, since we already
846 * disabled interrupts and not holding a spin lock */
847 synchronize_irq(sc->irq);
848 tasklet_kill(&sc->intr_tq);
849 tasklet_kill(&sc->bcon_tasklet);
850
Felix Fietkauc0c11742011-11-16 13:08:41 +0100851 prev_idle = sc->ps_idle;
852 sc->ps_idle = true;
853
854 spin_lock_bh(&sc->sc_pcu_lock);
855
856 if (ah->led_pin >= 0) {
857 ath9k_hw_set_gpio(ah, ah->led_pin, 1);
858 ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
859 }
860
John W. Linville9ebea382013-01-28 13:54:03 -0500861 ath_prepare_reset(sc);
Felix Fietkauc0c11742011-11-16 13:08:41 +0100862
863 if (sc->rx.frag) {
864 dev_kfree_skb_any(sc->rx.frag);
865 sc->rx.frag = NULL;
866 }
867
868 if (!ah->curchan)
Felix Fietkaufbbcd142014-06-11 16:17:49 +0530869 ah->curchan = ath9k_cmn_get_channel(hw, ah,
870 &sc->cur_chan->chandef);
Felix Fietkauc0c11742011-11-16 13:08:41 +0100871
872 ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
873 ath9k_hw_phy_disable(ah);
874
875 ath9k_hw_configpcipowersave(ah, true);
876
877 spin_unlock_bh(&sc->sc_pcu_lock);
878
Sujith3867cf62009-12-23 20:03:27 -0500879 ath9k_ps_restore(sc);
880
Oleksij Rempeleefa01d2014-02-27 11:40:46 +0100881 set_bit(ATH_OP_INVALID, &common->op_flags);
Felix Fietkauc0c11742011-11-16 13:08:41 +0100882 sc->ps_idle = prev_idle;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700883
Sujith141b38b2009-02-04 08:10:07 +0530884 mutex_unlock(&sc->mutex);
885
Joe Perchesd2182b62011-12-15 14:55:53 -0800886 ath_dbg(common, CONFIG, "Driver halt\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700887}
888
Felix Fietkauc648ecb2013-10-11 23:31:00 +0200889static bool ath9k_uses_beacons(int type)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700890{
Ben Greear48014162011-01-15 19:13:48 +0000891 switch (type) {
Johannes Berg05c914f2008-09-11 00:01:58 +0200892 case NL80211_IFTYPE_AP:
Ben Greear48014162011-01-15 19:13:48 +0000893 case NL80211_IFTYPE_ADHOC:
Pat Erley9cb54122009-03-20 22:59:59 -0400894 case NL80211_IFTYPE_MESH_POINT:
Ben Greear48014162011-01-15 19:13:48 +0000895 return true;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700896 default:
Ben Greear48014162011-01-15 19:13:48 +0000897 return false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700898 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -0700899}
900
Sujith Manoharan4b93fd22014-08-23 13:29:22 +0530901static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
902 u8 *mac, struct ieee80211_vif *vif)
Ben Greear48014162011-01-15 19:13:48 +0000903{
Sujith Manoharancb355822014-09-17 14:45:56 +0530904 struct ath_vif *avp = (struct ath_vif *)vif->drv_priv;
Ben Greear48014162011-01-15 19:13:48 +0000905 int i;
906
Felix Fietkauab11bb22013-04-16 12:51:57 +0200907 if (iter_data->has_hw_macaddr) {
Ben Greear48014162011-01-15 19:13:48 +0000908 for (i = 0; i < ETH_ALEN; i++)
909 iter_data->mask[i] &=
910 ~(iter_data->hw_macaddr[i] ^ mac[i]);
Felix Fietkauab11bb22013-04-16 12:51:57 +0200911 } else {
912 memcpy(iter_data->hw_macaddr, mac, ETH_ALEN);
913 iter_data->has_hw_macaddr = true;
914 }
Ben Greear48014162011-01-15 19:13:48 +0000915
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +0530916 if (!vif->bss_conf.use_short_slot)
917 iter_data->slottime = ATH9K_SLOT_TIME_20;
918
Ben Greear48014162011-01-15 19:13:48 +0000919 switch (vif->type) {
920 case NL80211_IFTYPE_AP:
921 iter_data->naps++;
922 break;
923 case NL80211_IFTYPE_STATION:
924 iter_data->nstations++;
Sujith Manoharancb355822014-09-17 14:45:56 +0530925 if (avp->assoc && !iter_data->primary_sta)
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +0530926 iter_data->primary_sta = vif;
Ben Greear48014162011-01-15 19:13:48 +0000927 break;
928 case NL80211_IFTYPE_ADHOC:
929 iter_data->nadhocs++;
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +0530930 if (vif->bss_conf.enable_beacon)
931 iter_data->beacons = true;
Ben Greear48014162011-01-15 19:13:48 +0000932 break;
933 case NL80211_IFTYPE_MESH_POINT:
934 iter_data->nmeshes++;
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +0530935 if (vif->bss_conf.enable_beacon)
936 iter_data->beacons = true;
Ben Greear48014162011-01-15 19:13:48 +0000937 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 Manoharan2ce73c02014-09-19 13:00:42 +0530946static void ath9k_update_bssid_mask(struct ath_softc *sc,
947 struct ath_chanctx *ctx,
948 struct ath9k_vif_iter_data *iter_data)
949{
950 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
951 struct ath_vif *avp;
952 int i;
953
954 if (!ath9k_is_chanctx_enabled())
955 return;
956
957 list_for_each_entry(avp, &ctx->vifs, list) {
958 if (ctx->nvifs_assigned != 1)
959 continue;
960
961 if (!avp->vif->p2p || !iter_data->has_hw_macaddr)
962 continue;
963
964 ether_addr_copy(common->curbssid, avp->bssid);
965
966 /* perm_addr will be used as the p2p device address. */
967 for (i = 0; i < ETH_ALEN; i++)
968 iter_data->mask[i] &=
969 ~(iter_data->hw_macaddr[i] ^
970 sc->hw->wiphy->perm_addr[i]);
971 }
972}
973
Ben Greear48014162011-01-15 19:13:48 +0000974/* Called with sc->mutex held. */
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +0530975void ath9k_calculate_iter_data(struct ath_softc *sc,
976 struct ath_chanctx *ctx,
Ben Greear48014162011-01-15 19:13:48 +0000977 struct ath9k_vif_iter_data *iter_data)
978{
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +0530979 struct ath_vif *avp;
Ben Greear48014162011-01-15 19:13:48 +0000980
981 /*
Mathy Vanhoef657eb172013-11-28 12:21:45 +0100982 * Pick the MAC address of the first interface as the new hardware
983 * MAC address. The hardware will use it together with the BSSID mask
984 * when matching addresses.
Ben Greear48014162011-01-15 19:13:48 +0000985 */
986 memset(iter_data, 0, sizeof(*iter_data));
Ben Greear48014162011-01-15 19:13:48 +0000987 memset(&iter_data->mask, 0xff, ETH_ALEN);
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +0530988 iter_data->slottime = ATH9K_SLOT_TIME_9;
Ben Greear48014162011-01-15 19:13:48 +0000989
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +0530990 list_for_each_entry(avp, &ctx->vifs, list)
991 ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif);
Sujith Manoharan2ce73c02014-09-19 13:00:42 +0530992
993 ath9k_update_bssid_mask(sc, ctx, iter_data);
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +0530994}
995
996static void ath9k_set_assoc_state(struct ath_softc *sc,
997 struct ieee80211_vif *vif, bool changed)
998{
999 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Sujith Manoharancb355822014-09-17 14:45:56 +05301000 struct ath_vif *avp = (struct ath_vif *)vif->drv_priv;
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301001 unsigned long flags;
1002
1003 set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301004
Sujith Manoharancb355822014-09-17 14:45:56 +05301005 ether_addr_copy(common->curbssid, avp->bssid);
1006 common->curaid = avp->aid;
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301007 ath9k_hw_write_associd(sc->sc_ah);
1008
1009 if (changed) {
1010 common->last_rssi = ATH_RSSI_DUMMY_MARKER;
1011 sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
1012
1013 spin_lock_irqsave(&sc->sc_pm_lock, flags);
1014 sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
1015 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
1016 }
1017
1018 if (ath9k_hw_mci_is_enabled(sc->sc_ah))
1019 ath9k_mci_update_wlan_channels(sc, false);
1020
1021 ath_dbg(common, CONFIG,
1022 "Primary Station interface: %pM, BSSID: %pM\n",
1023 vif->addr, common->curbssid);
Ben Greear48014162011-01-15 19:13:48 +00001024}
1025
Sujith Manoharan4ee26de2014-09-15 11:25:52 +05301026#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
1027static void ath9k_set_offchannel_state(struct ath_softc *sc)
1028{
1029 struct ath_hw *ah = sc->sc_ah;
1030 struct ath_common *common = ath9k_hw_common(ah);
1031 struct ieee80211_vif *vif = NULL;
1032
1033 ath9k_ps_wakeup(sc);
1034
1035 if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START)
1036 vif = sc->offchannel.scan_vif;
1037 else
1038 vif = sc->offchannel.roc_vif;
1039
1040 if (WARN_ON(!vif))
1041 goto exit;
1042
1043 eth_zero_addr(common->curbssid);
1044 eth_broadcast_addr(common->bssidmask);
1045 ether_addr_copy(common->macaddr, vif->addr);
1046 common->curaid = 0;
1047 ah->opmode = vif->type;
1048 ah->imask &= ~ATH9K_INT_SWBA;
1049 ah->imask &= ~ATH9K_INT_TSFOOR;
1050 ah->slottime = ATH9K_SLOT_TIME_9;
1051
1052 ath_hw_setbssidmask(common);
1053 ath9k_hw_setopmode(ah);
1054 ath9k_hw_write_associd(sc->sc_ah);
1055 ath9k_hw_set_interrupts(ah);
1056 ath9k_hw_init_global_settings(ah);
1057
1058exit:
1059 ath9k_ps_restore(sc);
1060}
1061#endif
1062
Ben Greear48014162011-01-15 19:13:48 +00001063/* Called with sc->mutex held. */
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301064void ath9k_calculate_summary_state(struct ath_softc *sc,
1065 struct ath_chanctx *ctx)
Ben Greear48014162011-01-15 19:13:48 +00001066{
Ben Greear48014162011-01-15 19:13:48 +00001067 struct ath_hw *ah = sc->sc_ah;
1068 struct ath_common *common = ath9k_hw_common(ah);
1069 struct ath9k_vif_iter_data iter_data;
Sujith Manoharan9bf30ff92014-09-05 08:03:11 +05301070 struct ath_beacon_config *cur_conf;
Ben Greear48014162011-01-15 19:13:48 +00001071
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301072 ath_chanctx_check_active(sc, ctx);
1073
1074 if (ctx != sc->cur_chan)
1075 return;
1076
Sujith Manoharan4ee26de2014-09-15 11:25:52 +05301077#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
1078 if (ctx == &sc->offchannel.chan)
1079 return ath9k_set_offchannel_state(sc);
1080#endif
1081
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301082 ath9k_ps_wakeup(sc);
1083 ath9k_calculate_iter_data(sc, ctx, &iter_data);
1084
1085 if (iter_data.has_hw_macaddr)
1086 ether_addr_copy(common->macaddr, iter_data.hw_macaddr);
Ben Greear48014162011-01-15 19:13:48 +00001087
Ben Greear48014162011-01-15 19:13:48 +00001088 memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
1089 ath_hw_setbssidmask(common);
1090
Ben Greear48014162011-01-15 19:13:48 +00001091 if (iter_data.naps > 0) {
Sujith Manoharan9bf30ff92014-09-05 08:03:11 +05301092 cur_conf = &ctx->beacon;
Sujith Manoharan60ca9f82012-07-17 17:15:37 +05301093 ath9k_hw_set_tsfadjust(ah, true);
Ben Greear48014162011-01-15 19:13:48 +00001094 ah->opmode = NL80211_IFTYPE_AP;
Sujith Manoharan9bf30ff92014-09-05 08:03:11 +05301095 if (cur_conf->enable_beacon)
1096 iter_data.beacons = true;
Ben Greear48014162011-01-15 19:13:48 +00001097 } else {
Sujith Manoharan60ca9f82012-07-17 17:15:37 +05301098 ath9k_hw_set_tsfadjust(ah, false);
Ben Greear48014162011-01-15 19:13:48 +00001099
Javier Cardonafd5999c2011-05-03 16:57:19 -07001100 if (iter_data.nmeshes)
1101 ah->opmode = NL80211_IFTYPE_MESH_POINT;
1102 else if (iter_data.nwds)
Ben Greear48014162011-01-15 19:13:48 +00001103 ah->opmode = NL80211_IFTYPE_AP;
1104 else if (iter_data.nadhocs)
1105 ah->opmode = NL80211_IFTYPE_ADHOC;
1106 else
1107 ah->opmode = NL80211_IFTYPE_STATION;
1108 }
1109
Sujith Manoharandf35d292012-07-17 17:15:43 +05301110 ath9k_hw_setopmode(ah);
1111
Felix Fietkau748299f2014-06-11 16:18:04 +05301112 ctx->switch_after_beacon = false;
Felix Fietkau198823f2012-06-15 15:25:25 +02001113 if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0)
Ben Greear48014162011-01-15 19:13:48 +00001114 ah->imask |= ATH9K_INT_TSFOOR;
Felix Fietkau748299f2014-06-11 16:18:04 +05301115 else {
Ben Greear48014162011-01-15 19:13:48 +00001116 ah->imask &= ~ATH9K_INT_TSFOOR;
Felix Fietkau748299f2014-06-11 16:18:04 +05301117 if (iter_data.naps == 1 && iter_data.beacons)
1118 ctx->switch_after_beacon = true;
1119 }
Ben Greear48014162011-01-15 19:13:48 +00001120
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301121 ah->imask &= ~ATH9K_INT_SWBA;
1122 if (ah->opmode == NL80211_IFTYPE_STATION) {
1123 bool changed = (iter_data.primary_sta != ctx->primary_sta);
1124
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301125 if (iter_data.primary_sta) {
Sujith Manoharan602607b2014-09-05 08:03:10 +05301126 iter_data.beacons = true;
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301127 ath9k_set_assoc_state(sc, iter_data.primary_sta,
1128 changed);
Sujith Manoharan1030f9f2014-09-15 11:25:54 +05301129 ctx->primary_sta = iter_data.primary_sta;
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301130 } else {
1131 ctx->primary_sta = NULL;
1132 memset(common->curbssid, 0, ETH_ALEN);
1133 common->curaid = 0;
1134 ath9k_hw_write_associd(sc->sc_ah);
1135 if (ath9k_hw_mci_is_enabled(sc->sc_ah))
1136 ath9k_mci_update_wlan_channels(sc, true);
1137 }
1138 } else if (iter_data.beacons) {
1139 ah->imask |= ATH9K_INT_SWBA;
1140 }
Felix Fietkau72d874c2011-10-08 20:06:19 +02001141 ath9k_hw_set_interrupts(ah);
Sujith Manoharan6dcc3442012-07-17 17:16:36 +05301142
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301143 if (iter_data.beacons)
1144 set_bit(ATH_OP_BEACONS, &common->op_flags);
1145 else
1146 clear_bit(ATH_OP_BEACONS, &common->op_flags);
1147
1148 if (ah->slottime != iter_data.slottime) {
1149 ah->slottime = iter_data.slottime;
1150 ath9k_hw_init_global_settings(ah);
Sujith Manoharan6dcc3442012-07-17 17:16:36 +05301151 }
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301152
1153 if (iter_data.primary_sta)
1154 set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
1155 else
1156 clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
1157
Sujith Manoharan2ce73c02014-09-19 13:00:42 +05301158 ath_dbg(common, CONFIG,
1159 "macaddr: %pM, bssid: %pM, bssidmask: %pM\n",
1160 common->macaddr, common->curbssid, common->bssidmask);
1161
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301162 ath9k_ps_restore(sc);
Ben Greear48014162011-01-15 19:13:48 +00001163}
1164
Sujith Manoharana4027642014-09-05 09:50:55 +05301165static void ath9k_assign_hw_queues(struct ieee80211_hw *hw,
1166 struct ieee80211_vif *vif)
1167{
1168 int i;
1169
1170 for (i = 0; i < IEEE80211_NUM_ACS; i++)
1171 vif->hw_queue[i] = i;
1172
1173 if (vif->type == NL80211_IFTYPE_AP)
1174 vif->cab_queue = hw->queues - 2;
1175 else
1176 vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
1177}
1178
Ben Greear48014162011-01-15 19:13:48 +00001179static int ath9k_add_interface(struct ieee80211_hw *hw,
1180 struct ieee80211_vif *vif)
1181{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001182 struct ath_softc *sc = hw->priv;
Ben Greear48014162011-01-15 19:13:48 +00001183 struct ath_hw *ah = sc->sc_ah;
1184 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkauf89d1bc2013-08-06 14:18:13 +02001185 struct ath_vif *avp = (void *)vif->drv_priv;
1186 struct ath_node *an = &avp->mcast_node;
Ben Greear48014162011-01-15 19:13:48 +00001187
1188 mutex_lock(&sc->mutex);
1189
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001190 if (config_enabled(CONFIG_ATH9K_TX99)) {
Sujith Manoharanca529c92014-09-05 08:03:19 +05301191 if (sc->cur_chan->nvifs >= 1) {
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001192 mutex_unlock(&sc->mutex);
1193 return -EOPNOTSUPP;
1194 }
1195 sc->tx99_vif = vif;
1196 }
1197
Joe Perchesd2182b62011-12-15 14:55:53 -08001198 ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
Sujith Manoharanca529c92014-09-05 08:03:19 +05301199 sc->cur_chan->nvifs++;
Ben Greear48014162011-01-15 19:13:48 +00001200
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301201 if (ath9k_uses_beacons(vif->type))
1202 ath9k_beacon_assign_slot(sc, vif);
1203
Felix Fietkaud463af42014-04-06 00:37:03 +02001204 avp->vif = vif;
Sujith Manoharan499afac2014-08-22 20:39:31 +05301205 if (!ath9k_is_chanctx_enabled()) {
Felix Fietkau39305632014-06-11 16:17:57 +05301206 avp->chanctx = sc->cur_chan;
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301207 list_add_tail(&avp->list, &avp->chanctx->vifs);
1208 }
Sujith Manoharana4027642014-09-05 09:50:55 +05301209
1210 ath9k_assign_hw_queues(hw, vif);
Felix Fietkau04535312014-06-11 16:17:51 +05301211
Felix Fietkauf89d1bc2013-08-06 14:18:13 +02001212 an->sc = sc;
1213 an->sta = NULL;
1214 an->vif = vif;
1215 an->no_ps_filter = true;
1216 ath_tx_node_init(sc, an);
1217
Ben Greear48014162011-01-15 19:13:48 +00001218 mutex_unlock(&sc->mutex);
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301219 return 0;
Ben Greear48014162011-01-15 19:13:48 +00001220}
1221
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301222static int ath9k_change_interface(struct ieee80211_hw *hw,
1223 struct ieee80211_vif *vif,
1224 enum nl80211_iftype new_type,
1225 bool p2p)
1226{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001227 struct ath_softc *sc = hw->priv;
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301228 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkauc083ce92014-06-11 16:17:54 +05301229 struct ath_vif *avp = (void *)vif->drv_priv;
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301230
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301231 mutex_lock(&sc->mutex);
Ben Greear48014162011-01-15 19:13:48 +00001232
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001233 if (config_enabled(CONFIG_ATH9K_TX99)) {
1234 mutex_unlock(&sc->mutex);
1235 return -EOPNOTSUPP;
1236 }
1237
1238 ath_dbg(common, CONFIG, "Change Interface\n");
1239
Ben Greear48014162011-01-15 19:13:48 +00001240 if (ath9k_uses_beacons(vif->type))
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301241 ath9k_beacon_remove_slot(sc, vif);
Ben Greear48014162011-01-15 19:13:48 +00001242
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301243 vif->type = new_type;
1244 vif->p2p = p2p;
1245
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301246 if (ath9k_uses_beacons(vif->type))
1247 ath9k_beacon_assign_slot(sc, vif);
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301248
Sujith Manoharana4027642014-09-05 09:50:55 +05301249 ath9k_assign_hw_queues(hw, vif);
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301250 ath9k_calculate_summary_state(sc, avp->chanctx);
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301251
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301252 mutex_unlock(&sc->mutex);
Mohammed Shafi Shajakhan327967c2012-09-04 19:33:36 +05301253 return 0;
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05301254}
1255
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001256static void ath9k_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001257 struct ieee80211_vif *vif)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001258{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001259 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001260 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkauf89d1bc2013-08-06 14:18:13 +02001261 struct ath_vif *avp = (void *)vif->drv_priv;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001262
Joe Perchesd2182b62011-12-15 14:55:53 -08001263 ath_dbg(common, CONFIG, "Detach Interface\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001264
Sujith141b38b2009-02-04 08:10:07 +05301265 mutex_lock(&sc->mutex);
1266
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +05301267 ath9k_p2p_remove_vif(sc, vif);
Felix Fietkaud463af42014-04-06 00:37:03 +02001268
Sujith Manoharanca529c92014-09-05 08:03:19 +05301269 sc->cur_chan->nvifs--;
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001270 sc->tx99_vif = NULL;
Sujith Manoharan499afac2014-08-22 20:39:31 +05301271 if (!ath9k_is_chanctx_enabled())
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301272 list_del(&avp->list);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001273
Ben Greear48014162011-01-15 19:13:48 +00001274 if (ath9k_uses_beacons(vif->type))
Sujith Manoharan130ef6e2012-07-17 17:15:30 +05301275 ath9k_beacon_remove_slot(sc, vif);
Jouni Malinen2c3db3d2009-03-03 19:23:26 +02001276
Felix Fietkauf89d1bc2013-08-06 14:18:13 +02001277 ath_tx_node_cleanup(sc, &avp->mcast_node);
1278
Sujith141b38b2009-02-04 08:10:07 +05301279 mutex_unlock(&sc->mutex);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001280}
1281
Senthil Balasubramanianfbab7392010-10-05 20:36:40 +05301282static void ath9k_enable_ps(struct ath_softc *sc)
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301283{
Pavel Roskin30691682010-03-31 18:05:31 -04001284 struct ath_hw *ah = sc->sc_ah;
Sujith Manoharanad128862012-04-24 10:23:20 +05301285 struct ath_common *common = ath9k_hw_common(ah);
Pavel Roskin30691682010-03-31 18:05:31 -04001286
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001287 if (config_enabled(CONFIG_ATH9K_TX99))
1288 return;
1289
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301290 sc->ps_enabled = true;
Pavel Roskin30691682010-03-31 18:05:31 -04001291 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
1292 if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) {
1293 ah->imask |= ATH9K_INT_TIM_TIMER;
Felix Fietkau72d874c2011-10-08 20:06:19 +02001294 ath9k_hw_set_interrupts(ah);
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301295 }
Vasanthakumar Thiagarajanfdf76622010-05-17 18:57:55 -07001296 ath9k_hw_setrxabort(ah, 1);
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301297 }
Sujith Manoharanad128862012-04-24 10:23:20 +05301298 ath_dbg(common, PS, "PowerSave enabled\n");
Senthil Balasubramanian3f7c5c12010-02-03 22:51:13 +05301299}
1300
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301301static void ath9k_disable_ps(struct ath_softc *sc)
1302{
1303 struct ath_hw *ah = sc->sc_ah;
Sujith Manoharanad128862012-04-24 10:23:20 +05301304 struct ath_common *common = ath9k_hw_common(ah);
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301305
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001306 if (config_enabled(CONFIG_ATH9K_TX99))
1307 return;
1308
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301309 sc->ps_enabled = false;
1310 ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
1311 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
1312 ath9k_hw_setrxabort(ah, 0);
1313 sc->ps_flags &= ~(PS_WAIT_FOR_BEACON |
1314 PS_WAIT_FOR_CAB |
1315 PS_WAIT_FOR_PSPOLL_DATA |
1316 PS_WAIT_FOR_TX_ACK);
1317 if (ah->imask & ATH9K_INT_TIM_TIMER) {
1318 ah->imask &= ~ATH9K_INT_TIM_TIMER;
Felix Fietkau72d874c2011-10-08 20:06:19 +02001319 ath9k_hw_set_interrupts(ah);
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301320 }
1321 }
Sujith Manoharanad128862012-04-24 10:23:20 +05301322 ath_dbg(common, PS, "PowerSave disabled\n");
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301323}
1324
Simon Wunderliche93d0832013-01-08 14:48:58 +01001325void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw)
1326{
1327 struct ath_softc *sc = hw->priv;
1328 struct ath_hw *ah = sc->sc_ah;
1329 struct ath_common *common = ath9k_hw_common(ah);
1330 u32 rxfilter;
1331
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001332 if (config_enabled(CONFIG_ATH9K_TX99))
1333 return;
1334
Simon Wunderliche93d0832013-01-08 14:48:58 +01001335 if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
1336 ath_err(common, "spectrum analyzer not implemented on this hardware\n");
1337 return;
1338 }
1339
1340 ath9k_ps_wakeup(sc);
1341 rxfilter = ath9k_hw_getrxfilter(ah);
1342 ath9k_hw_setrxfilter(ah, rxfilter |
1343 ATH9K_RX_FILTER_PHYRADAR |
1344 ATH9K_RX_FILTER_PHYERR);
1345
1346 /* TODO: usually this should not be neccesary, but for some reason
1347 * (or in some mode?) the trigger must be called after the
1348 * configuration, otherwise the register will have its values reset
1349 * (on my ar9220 to value 0x01002310)
1350 */
1351 ath9k_spectral_scan_config(hw, sc->spectral_mode);
1352 ath9k_hw_ops(ah)->spectral_scan_trigger(ah);
1353 ath9k_ps_restore(sc);
1354}
1355
1356int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
1357 enum spectral_mode spectral_mode)
1358{
1359 struct ath_softc *sc = hw->priv;
1360 struct ath_hw *ah = sc->sc_ah;
1361 struct ath_common *common = ath9k_hw_common(ah);
Simon Wunderliche93d0832013-01-08 14:48:58 +01001362
1363 if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
1364 ath_err(common, "spectrum analyzer not implemented on this hardware\n");
1365 return -1;
1366 }
1367
Simon Wunderliche93d0832013-01-08 14:48:58 +01001368 switch (spectral_mode) {
1369 case SPECTRAL_DISABLED:
Simon Wunderlich04ccd4a2013-01-23 17:38:04 +01001370 sc->spec_config.enabled = 0;
Simon Wunderliche93d0832013-01-08 14:48:58 +01001371 break;
1372 case SPECTRAL_BACKGROUND:
1373 /* send endless samples.
1374 * TODO: is this really useful for "background"?
1375 */
Simon Wunderlich04ccd4a2013-01-23 17:38:04 +01001376 sc->spec_config.endless = 1;
1377 sc->spec_config.enabled = 1;
Simon Wunderliche93d0832013-01-08 14:48:58 +01001378 break;
1379 case SPECTRAL_CHANSCAN:
Simon Wunderliche93d0832013-01-08 14:48:58 +01001380 case SPECTRAL_MANUAL:
Simon Wunderlich04ccd4a2013-01-23 17:38:04 +01001381 sc->spec_config.endless = 0;
1382 sc->spec_config.enabled = 1;
Simon Wunderliche93d0832013-01-08 14:48:58 +01001383 break;
1384 default:
1385 return -1;
1386 }
1387
1388 ath9k_ps_wakeup(sc);
Simon Wunderlich04ccd4a2013-01-23 17:38:04 +01001389 ath9k_hw_ops(ah)->spectral_scan_config(ah, &sc->spec_config);
Simon Wunderliche93d0832013-01-08 14:48:58 +01001390 ath9k_ps_restore(sc);
1391
1392 sc->spectral_mode = spectral_mode;
1393
1394 return 0;
1395}
1396
Johannes Berge8975582008-10-09 12:18:51 +02001397static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001398{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001399 struct ath_softc *sc = hw->priv;
Felix Fietkau34300982010-10-10 18:21:52 +02001400 struct ath_hw *ah = sc->sc_ah;
1401 struct ath_common *common = ath9k_hw_common(ah);
Johannes Berge8975582008-10-09 12:18:51 +02001402 struct ieee80211_conf *conf = &hw->conf;
Felix Fietkaufbbcd142014-06-11 16:17:49 +05301403 struct ath_chanctx *ctx = sc->cur_chan;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001404
Felix Fietkauc0c11742011-11-16 13:08:41 +01001405 ath9k_ps_wakeup(sc);
Sujithaa33de02008-12-18 11:40:16 +05301406 mutex_lock(&sc->mutex);
Sujith141b38b2009-02-04 08:10:07 +05301407
Felix Fietkaudaa1b6e2011-11-16 13:08:43 +01001408 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Felix Fietkau7545daf2011-01-24 19:23:16 +01001409 sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
Rajkumar Manoharanb73f3e72012-07-01 19:53:53 +05301410 if (sc->ps_idle) {
Felix Fietkaudaa1b6e2011-11-16 13:08:43 +01001411 ath_cancel_work(sc);
Rajkumar Manoharanb73f3e72012-07-01 19:53:53 +05301412 ath9k_stop_btcoex(sc);
1413 } else {
1414 ath9k_start_btcoex(sc);
Felix Fietkau75600ab2012-04-12 20:36:31 +02001415 /*
1416 * The chip needs a reset to properly wake up from
1417 * full sleep
1418 */
Felix Fietkau39305632014-06-11 16:17:57 +05301419 ath_chanctx_set_channel(sc, ctx, &ctx->chandef);
Rajkumar Manoharanb73f3e72012-07-01 19:53:53 +05301420 }
Felix Fietkaudaa1b6e2011-11-16 13:08:43 +01001421 }
Luis R. Rodriguez64839172009-07-14 20:22:53 -04001422
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -05001423 /*
1424 * We just prepare to enable PS. We have to wait until our AP has
1425 * ACK'd our null data frame to disable RX otherwise we'll ignore
1426 * those ACKs and end up retransmitting the same null data frames.
1427 * IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode.
1428 */
Vivek Natarajan3cbb5dd2009-01-20 11:17:08 +05301429 if (changed & IEEE80211_CONF_CHANGE_PS) {
Luis R. Rodriguez8ab2cd02010-09-16 15:12:26 -04001430 unsigned long flags;
1431 spin_lock_irqsave(&sc->sc_pm_lock, flags);
Senthil Balasubramanianfbab7392010-10-05 20:36:40 +05301432 if (conf->flags & IEEE80211_CONF_PS)
1433 ath9k_enable_ps(sc);
Senthil Balasubramanian845d7082010-10-05 20:36:41 +05301434 else
1435 ath9k_disable_ps(sc);
Luis R. Rodriguez8ab2cd02010-09-16 15:12:26 -04001436 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
Vivek Natarajan3cbb5dd2009-01-20 11:17:08 +05301437 }
1438
Sujith199afd92010-01-08 10:36:13 +05301439 if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
1440 if (conf->flags & IEEE80211_CONF_MONITOR) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001441 ath_dbg(common, CONFIG, "Monitor mode is enabled\n");
Rajkumar Manoharan5f841b42010-10-27 18:31:15 +05301442 sc->sc_ah->is_monitoring = true;
1443 } else {
Joe Perchesd2182b62011-12-15 14:55:53 -08001444 ath_dbg(common, CONFIG, "Monitor mode is disabled\n");
Rajkumar Manoharan5f841b42010-10-27 18:31:15 +05301445 sc->sc_ah->is_monitoring = false;
Sujith199afd92010-01-08 10:36:13 +05301446 }
1447 }
1448
Sujith Manoharan499afac2014-08-22 20:39:31 +05301449 if (!ath9k_is_chanctx_enabled() && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
Felix Fietkaufbbcd142014-06-11 16:17:49 +05301450 ctx->offchannel = !!(conf->flags & IEEE80211_CONF_OFFCHANNEL);
Felix Fietkaubff11762014-06-11 16:17:52 +05301451 ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef);
Sujith094d05d2008-12-12 11:57:43 +05301452 }
Sujith86b89ee2008-08-07 10:54:57 +05301453
Luis R. Rodriguezc9f6a652010-01-19 14:04:19 -05001454 if (changed & IEEE80211_CONF_CHANGE_POWER) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001455 ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level);
Felix Fietkaubc7e1be2014-06-11 16:17:50 +05301456 sc->cur_chan->txpower = 2 * conf->power_level;
Rajkumar Manoharan5048e8c2011-01-31 23:47:44 +05301457 ath9k_cmn_update_txpow(ah, sc->curtxpow,
Felix Fietkaubc7e1be2014-06-11 16:17:50 +05301458 sc->cur_chan->txpower, &sc->curtxpow);
Luis R. Rodriguez64839172009-07-14 20:22:53 -04001459 }
1460
Sujithaa33de02008-12-18 11:40:16 +05301461 mutex_unlock(&sc->mutex);
Felix Fietkauc0c11742011-11-16 13:08:41 +01001462 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301463
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001464 return 0;
1465}
1466
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001467#define SUPPORTED_FILTERS \
1468 (FIF_PROMISC_IN_BSS | \
1469 FIF_ALLMULTI | \
1470 FIF_CONTROL | \
Luis R. Rodriguezaf6a3fc2009-08-08 21:55:16 -04001471 FIF_PSPOLL | \
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001472 FIF_OTHER_BSS | \
1473 FIF_BCN_PRBRESP_PROMISC | \
Jouni Malinen9c1d8e42010-10-13 17:29:31 +03001474 FIF_PROBE_REQ | \
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001475 FIF_FCSFAIL)
1476
Sujith7dcfdcd2008-08-11 14:03:13 +05301477/* FIXME: sc->sc_full_reset ? */
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001478static void ath9k_configure_filter(struct ieee80211_hw *hw,
1479 unsigned int changed_flags,
1480 unsigned int *total_flags,
Johannes Berg3ac64be2009-08-17 16:16:53 +02001481 u64 multicast)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001482{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001483 struct ath_softc *sc = hw->priv;
Sujith7dcfdcd2008-08-11 14:03:13 +05301484 u32 rfilt;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001485
1486 changed_flags &= SUPPORTED_FILTERS;
1487 *total_flags &= SUPPORTED_FILTERS;
1488
Sujith Manoharanfce34432014-09-05 08:03:18 +05301489 spin_lock_bh(&sc->chan_lock);
1490 sc->cur_chan->rxfilter = *total_flags;
1491 spin_unlock_bh(&sc->chan_lock);
1492
Jouni Malinenaa68aea2009-05-19 17:01:41 +03001493 ath9k_ps_wakeup(sc);
Sujith7dcfdcd2008-08-11 14:03:13 +05301494 rfilt = ath_calcrxfilter(sc);
1495 ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
Jouni Malinenaa68aea2009-05-19 17:01:41 +03001496 ath9k_ps_restore(sc);
Sujith7dcfdcd2008-08-11 14:03:13 +05301497
Joe Perchesd2182b62011-12-15 14:55:53 -08001498 ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG, "Set HW RX filter: 0x%x\n",
1499 rfilt);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001500}
1501
Johannes Berg4ca77862010-02-19 19:06:56 +01001502static int ath9k_sta_add(struct ieee80211_hw *hw,
1503 struct ieee80211_vif *vif,
1504 struct ieee80211_sta *sta)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001505{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001506 struct ath_softc *sc = hw->priv;
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001507 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1508 struct ath_node *an = (struct ath_node *) sta->drv_priv;
1509 struct ieee80211_key_conf ps_key = { };
Felix Fietkau4ef69d02013-04-27 11:47:01 +02001510 int key;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001511
Ben Greear7e1e3862011-11-03 11:33:13 -07001512 ath_node_attach(sc, sta, vif);
Felix Fietkauf59a59f2011-05-10 20:52:22 +02001513
1514 if (vif->type != NL80211_IFTYPE_AP &&
1515 vif->type != NL80211_IFTYPE_AP_VLAN)
1516 return 0;
1517
Felix Fietkau4ef69d02013-04-27 11:47:01 +02001518 key = ath_key_config(common, vif, sta, &ps_key);
Rajkumar Manoharan4bbf4412014-05-22 12:35:49 +05301519 if (key > 0) {
Felix Fietkau4ef69d02013-04-27 11:47:01 +02001520 an->ps_key = key;
Rajkumar Manoharan4bbf4412014-05-22 12:35:49 +05301521 an->key_idx[0] = key;
1522 }
Johannes Berg4ca77862010-02-19 19:06:56 +01001523
1524 return 0;
1525}
1526
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001527static void ath9k_del_ps_key(struct ath_softc *sc,
1528 struct ieee80211_vif *vif,
1529 struct ieee80211_sta *sta)
1530{
1531 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1532 struct ath_node *an = (struct ath_node *) sta->drv_priv;
1533 struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key };
1534
1535 if (!an->ps_key)
1536 return;
1537
1538 ath_key_delete(common, &ps_key);
Felix Fietkau4ef69d02013-04-27 11:47:01 +02001539 an->ps_key = 0;
Rajkumar Manoharan4bbf4412014-05-22 12:35:49 +05301540 an->key_idx[0] = 0;
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001541}
1542
Johannes Berg4ca77862010-02-19 19:06:56 +01001543static int ath9k_sta_remove(struct ieee80211_hw *hw,
1544 struct ieee80211_vif *vif,
1545 struct ieee80211_sta *sta)
1546{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001547 struct ath_softc *sc = hw->priv;
Johannes Berg4ca77862010-02-19 19:06:56 +01001548
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001549 ath9k_del_ps_key(sc, vif, sta);
Johannes Berg4ca77862010-02-19 19:06:56 +01001550 ath_node_detach(sc, sta);
1551
1552 return 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001553}
1554
Rajkumar Manoharan4bbf4412014-05-22 12:35:49 +05301555static void ath9k_sta_set_tx_filter(struct ath_hw *ah,
1556 struct ath_node *an,
1557 bool set)
1558{
1559 int i;
1560
1561 for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) {
1562 if (!an->key_idx[i])
1563 continue;
1564 ath9k_hw_set_tx_filter(ah, an->key_idx[i], set);
1565 }
1566}
1567
Felix Fietkau55195412011-04-17 23:28:09 +02001568static void ath9k_sta_notify(struct ieee80211_hw *hw,
1569 struct ieee80211_vif *vif,
1570 enum sta_notify_cmd cmd,
1571 struct ieee80211_sta *sta)
1572{
1573 struct ath_softc *sc = hw->priv;
1574 struct ath_node *an = (struct ath_node *) sta->drv_priv;
1575
1576 switch (cmd) {
1577 case STA_NOTIFY_SLEEP:
1578 an->sleeping = true;
Johannes Berg042ec452011-09-29 16:04:26 +02001579 ath_tx_aggr_sleep(sta, sc, an);
Rajkumar Manoharan4bbf4412014-05-22 12:35:49 +05301580 ath9k_sta_set_tx_filter(sc->sc_ah, an, true);
Felix Fietkau55195412011-04-17 23:28:09 +02001581 break;
1582 case STA_NOTIFY_AWAKE:
Rajkumar Manoharan4bbf4412014-05-22 12:35:49 +05301583 ath9k_sta_set_tx_filter(sc->sc_ah, an, false);
Felix Fietkau55195412011-04-17 23:28:09 +02001584 an->sleeping = false;
1585 ath_tx_aggr_wakeup(sc, an);
1586 break;
1587 }
1588}
1589
Eliad Peller8a3a3c82011-10-02 10:15:52 +02001590static int ath9k_conf_tx(struct ieee80211_hw *hw,
1591 struct ieee80211_vif *vif, u16 queue,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001592 const struct ieee80211_tx_queue_params *params)
1593{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001594 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001595 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau066dae92010-11-07 14:59:39 +01001596 struct ath_txq *txq;
Sujithea9880f2008-08-07 10:53:10 +05301597 struct ath9k_tx_queue_info qi;
Felix Fietkau066dae92010-11-07 14:59:39 +01001598 int ret = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001599
Sujith Manoharanbea843c2012-11-21 18:13:10 +05301600 if (queue >= IEEE80211_NUM_ACS)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001601 return 0;
1602
Felix Fietkau066dae92010-11-07 14:59:39 +01001603 txq = sc->tx.txq_map[queue];
1604
Felix Fietkau96f372c2011-04-07 19:07:17 +02001605 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301606 mutex_lock(&sc->mutex);
1607
Sujith1ffb0612009-03-30 15:28:46 +05301608 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
1609
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001610 qi.tqi_aifs = params->aifs;
1611 qi.tqi_cwmin = params->cw_min;
1612 qi.tqi_cwmax = params->cw_max;
Felix Fietkau531bd072012-07-15 19:53:34 +02001613 qi.tqi_burstTime = params->txop * 32;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001614
Joe Perchesd2182b62011-12-15 14:55:53 -08001615 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -08001616 "Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
1617 queue, txq->axq_qnum, params->aifs, params->cw_min,
1618 params->cw_max, params->txop);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001619
Felix Fietkauaa5955c2012-07-15 19:53:36 +02001620 ath_update_max_aggr_framelen(sc, queue, qi.tqi_burstTime);
Felix Fietkau066dae92010-11-07 14:59:39 +01001621 ret = ath_txq_update(sc, txq->axq_qnum, &qi);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001622 if (ret)
Joe Perches38002762010-12-02 19:12:36 -08001623 ath_err(common, "TXQ Update failed\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001624
Sujith141b38b2009-02-04 08:10:07 +05301625 mutex_unlock(&sc->mutex);
Felix Fietkau96f372c2011-04-07 19:07:17 +02001626 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301627
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001628 return ret;
1629}
1630
1631static int ath9k_set_key(struct ieee80211_hw *hw,
1632 enum set_key_cmd cmd,
Johannes Bergdc822b52008-12-29 12:55:09 +01001633 struct ieee80211_vif *vif,
1634 struct ieee80211_sta *sta,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001635 struct ieee80211_key_conf *key)
1636{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001637 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001638 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Rajkumar Manoharan4bbf4412014-05-22 12:35:49 +05301639 struct ath_node *an = NULL;
1640 int ret = 0, i;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001641
John W. Linville3e6109c2011-01-05 09:39:17 -05001642 if (ath9k_modparam_nohwcrypt)
Jouni Malinenb3bd89c2009-02-24 13:42:01 +02001643 return -ENOSPC;
1644
Chun-Yeow Yeoh5bd5e9a2011-12-07 12:45:46 -08001645 if ((vif->type == NL80211_IFTYPE_ADHOC ||
1646 vif->type == NL80211_IFTYPE_MESH_POINT) &&
Jouni Malinencfdc9a82011-03-23 14:52:19 +02001647 (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
1648 key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
1649 !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
1650 /*
1651 * For now, disable hw crypto for the RSN IBSS group keys. This
1652 * could be optimized in the future to use a modified key cache
1653 * design to support per-STA RX GTK, but until that gets
1654 * implemented, use of software crypto for group addressed
1655 * frames is a acceptable to allow RSN IBSS to be used.
1656 */
1657 return -EOPNOTSUPP;
1658 }
1659
Sujith141b38b2009-02-04 08:10:07 +05301660 mutex_lock(&sc->mutex);
Vivek Natarajan3cbb5dd2009-01-20 11:17:08 +05301661 ath9k_ps_wakeup(sc);
Rajkumar Manoharan4bbf4412014-05-22 12:35:49 +05301662 ath_dbg(common, CONFIG, "Set HW Key %d\n", cmd);
1663 if (sta)
1664 an = (struct ath_node *)sta->drv_priv;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001665
1666 switch (cmd) {
1667 case SET_KEY:
Felix Fietkau93ae2dd2011-04-17 23:28:10 +02001668 if (sta)
1669 ath9k_del_ps_key(sc, vif, sta);
1670
Rajkumar Manoharan4bbf4412014-05-22 12:35:49 +05301671 key->hw_key_idx = 0;
Bruno Randolf040e5392010-09-08 16:05:04 +09001672 ret = ath_key_config(common, vif, sta, key);
Jouni Malinen6ace2892008-12-17 13:32:17 +02001673 if (ret >= 0) {
1674 key->hw_key_idx = ret;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001675 /* push IV and Michael MIC generation to stack */
1676 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Johannes Berg97359d12010-08-10 09:46:38 +02001677 if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
Senthil Balasubramanian1b961752008-09-01 19:45:21 +05301678 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
Johannes Berg97359d12010-08-10 09:46:38 +02001679 if (sc->sc_ah->sw_mgmt_crypto &&
1680 key->cipher == WLAN_CIPHER_SUITE_CCMP)
Johannes Berge548c492012-09-04 17:08:23 +02001681 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
Jouni Malinen6ace2892008-12-17 13:32:17 +02001682 ret = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001683 }
Rajkumar Manoharan4bbf4412014-05-22 12:35:49 +05301684 if (an && key->hw_key_idx) {
1685 for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) {
1686 if (an->key_idx[i])
1687 continue;
1688 an->key_idx[i] = key->hw_key_idx;
1689 break;
1690 }
1691 WARN_ON(i == ARRAY_SIZE(an->key_idx));
1692 }
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001693 break;
1694 case DISABLE_KEY:
Bruno Randolf040e5392010-09-08 16:05:04 +09001695 ath_key_delete(common, key);
Rajkumar Manoharan4bbf4412014-05-22 12:35:49 +05301696 if (an) {
1697 for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) {
1698 if (an->key_idx[i] != key->hw_key_idx)
1699 continue;
1700 an->key_idx[i] = 0;
1701 break;
1702 }
1703 }
1704 key->hw_key_idx = 0;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001705 break;
1706 default:
1707 ret = -EINVAL;
1708 }
1709
Vivek Natarajan3cbb5dd2009-01-20 11:17:08 +05301710 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301711 mutex_unlock(&sc->mutex);
1712
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001713 return ret;
1714}
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301715
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001716static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
1717 struct ieee80211_vif *vif,
1718 struct ieee80211_bss_conf *bss_conf,
1719 u32 changed)
1720{
Sujith Manoharanda0d45f2012-07-17 17:16:29 +05301721#define CHECK_ANI \
1722 (BSS_CHANGED_ASSOC | \
1723 BSS_CHANGED_IBSS | \
1724 BSS_CHANGED_BEACON_ENABLED)
1725
Felix Fietkau9ac586152011-01-24 19:23:18 +01001726 struct ath_softc *sc = hw->priv;
Johannes Berg2d0ddec2009-04-23 16:13:26 +02001727 struct ath_hw *ah = sc->sc_ah;
Luis R. Rodriguez15107182009-09-10 09:22:37 -07001728 struct ath_common *common = ath9k_hw_common(ah);
Johannes Berg2d0ddec2009-04-23 16:13:26 +02001729 struct ath_vif *avp = (void *)vif->drv_priv;
Felix Fietkau0005baf2010-01-15 02:33:40 +01001730 int slottime;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001731
Felix Fietkau96f372c2011-04-07 19:07:17 +02001732 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301733 mutex_lock(&sc->mutex);
1734
Rajkumar Manoharan9f619032012-03-10 05:06:49 +05301735 if (changed & BSS_CHANGED_ASSOC) {
Sujith Manoharan6c43c0902012-07-17 17:15:50 +05301736 ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n",
1737 bss_conf->bssid, bss_conf->assoc);
Sujithc6089cc2009-11-16 11:40:48 +05301738
Sujith Manoharancb355822014-09-17 14:45:56 +05301739 ether_addr_copy(avp->bssid, bss_conf->bssid);
1740 avp->aid = bss_conf->aid;
1741 avp->assoc = bss_conf->assoc;
1742
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301743 ath9k_calculate_summary_state(sc, avp->chanctx);
Sujith Manoharan27babf92014-08-23 13:29:16 +05301744
1745 if (ath9k_is_chanctx_enabled()) {
1746 if (bss_conf->assoc)
1747 ath_chanctx_event(sc, vif,
1748 ATH_CHANCTX_EVENT_ASSOC);
1749 }
Johannes Berg2d0ddec2009-04-23 16:13:26 +02001750 }
1751
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301752 if (changed & BSS_CHANGED_IBSS) {
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301753 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1754 common->curaid = bss_conf->aid;
1755 ath9k_hw_write_associd(sc->sc_ah);
Rajkumar Manoharan2e5ef452011-05-20 17:52:12 +05301756 }
1757
Sujith Manoharanef4ad632012-07-17 17:15:56 +05301758 if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
Rajkumar Manoharan9198cf42014-06-26 16:54:40 +05301759 (changed & BSS_CHANGED_BEACON_INT) ||
1760 (changed & BSS_CHANGED_BEACON_INFO)) {
Sujith Manoharan9bf30ff92014-09-05 08:03:11 +05301761 ath9k_beacon_config(sc, vif, changed);
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301762 if (changed & BSS_CHANGED_BEACON_ENABLED)
1763 ath9k_calculate_summary_state(sc, avp->chanctx);
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301764 }
Johannes Berg2d0ddec2009-04-23 16:13:26 +02001765
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05301766 if ((avp->chanctx == sc->cur_chan) &&
1767 (changed & BSS_CHANGED_ERP_SLOT)) {
Felix Fietkau0005baf2010-01-15 02:33:40 +01001768 if (bss_conf->use_short_slot)
1769 slottime = 9;
1770 else
1771 slottime = 20;
1772 if (vif->type == NL80211_IFTYPE_AP) {
1773 /*
1774 * Defer update, so that connected stations can adjust
1775 * their settings at the same time.
1776 * See beacon.c for more details
1777 */
1778 sc->beacon.slottime = slottime;
1779 sc->beacon.updateslot = UPDATE;
1780 } else {
1781 ah->slottime = slottime;
1782 ath9k_hw_init_global_settings(ah);
1783 }
1784 }
1785
Sujith Manoharanc7dd40c2014-08-22 20:39:30 +05301786 if (changed & BSS_CHANGED_P2P_PS)
1787 ath9k_p2p_bss_info_changed(sc, vif);
Felix Fietkaud463af42014-04-06 00:37:03 +02001788
Sujith Manoharanda0d45f2012-07-17 17:16:29 +05301789 if (changed & CHECK_ANI)
1790 ath_check_ani(sc);
1791
Sujith141b38b2009-02-04 08:10:07 +05301792 mutex_unlock(&sc->mutex);
Felix Fietkau96f372c2011-04-07 19:07:17 +02001793 ath9k_ps_restore(sc);
Sujith Manoharanda0d45f2012-07-17 17:16:29 +05301794
1795#undef CHECK_ANI
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001796}
1797
Eliad Peller37a41b42011-09-21 14:06:11 +03001798static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001799{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001800 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001801 u64 tsf;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001802
Sujith141b38b2009-02-04 08:10:07 +05301803 mutex_lock(&sc->mutex);
Sujith Manoharan9abbfb22010-12-10 11:27:06 +05301804 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301805 tsf = ath9k_hw_gettsf64(sc->sc_ah);
Sujith Manoharan9abbfb22010-12-10 11:27:06 +05301806 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301807 mutex_unlock(&sc->mutex);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001808
1809 return tsf;
1810}
1811
Eliad Peller37a41b42011-09-21 14:06:11 +03001812static void ath9k_set_tsf(struct ieee80211_hw *hw,
1813 struct ieee80211_vif *vif,
1814 u64 tsf)
Alina Friedrichsen3b5d6652009-01-24 07:09:59 +01001815{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001816 struct ath_softc *sc = hw->priv;
Alina Friedrichsen3b5d6652009-01-24 07:09:59 +01001817
Sujith141b38b2009-02-04 08:10:07 +05301818 mutex_lock(&sc->mutex);
Sujith Manoharan9abbfb22010-12-10 11:27:06 +05301819 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301820 ath9k_hw_settsf64(sc->sc_ah, tsf);
Sujith Manoharan9abbfb22010-12-10 11:27:06 +05301821 ath9k_ps_restore(sc);
Sujith141b38b2009-02-04 08:10:07 +05301822 mutex_unlock(&sc->mutex);
Alina Friedrichsen3b5d6652009-01-24 07:09:59 +01001823}
1824
Eliad Peller37a41b42011-09-21 14:06:11 +03001825static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001826{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001827 struct ath_softc *sc = hw->priv;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001828
Sujith141b38b2009-02-04 08:10:07 +05301829 mutex_lock(&sc->mutex);
Luis R. Rodriguez21526d52009-09-09 20:05:39 -07001830
1831 ath9k_ps_wakeup(sc);
Sujith141b38b2009-02-04 08:10:07 +05301832 ath9k_hw_reset_tsf(sc->sc_ah);
Luis R. Rodriguez21526d52009-09-09 20:05:39 -07001833 ath9k_ps_restore(sc);
1834
Sujith141b38b2009-02-04 08:10:07 +05301835 mutex_unlock(&sc->mutex);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001836}
1837
1838static int ath9k_ampdu_action(struct ieee80211_hw *hw,
Johannes Bergc951ad32009-11-16 12:00:38 +01001839 struct ieee80211_vif *vif,
Sujith141b38b2009-02-04 08:10:07 +05301840 enum ieee80211_ampdu_mlme_action action,
1841 struct ieee80211_sta *sta,
Johannes Berg0b01f032011-01-18 13:51:05 +01001842 u16 tid, u16 *ssn, u8 buf_size)
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001843{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001844 struct ath_softc *sc = hw->priv;
Felix Fietkau16e23422013-05-17 12:58:24 +02001845 bool flush = false;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001846 int ret = 0;
1847
Sujith Manoharan7ca7c772013-05-08 05:03:32 +05301848 mutex_lock(&sc->mutex);
Johannes Berg85ad1812010-06-10 10:21:49 +02001849
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001850 switch (action) {
1851 case IEEE80211_AMPDU_RX_START:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001852 break;
1853 case IEEE80211_AMPDU_RX_STOP:
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001854 break;
1855 case IEEE80211_AMPDU_TX_START:
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001856 ath9k_ps_wakeup(sc);
Felix Fietkau231c3a12010-09-20 19:35:28 +02001857 ret = ath_tx_aggr_start(sc, sta, tid, ssn);
1858 if (!ret)
1859 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001860 ath9k_ps_restore(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001861 break;
Johannes Berg18b559d2012-07-18 13:51:25 +02001862 case IEEE80211_AMPDU_TX_STOP_FLUSH:
1863 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
Felix Fietkau16e23422013-05-17 12:58:24 +02001864 flush = true;
1865 case IEEE80211_AMPDU_TX_STOP_CONT:
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001866 ath9k_ps_wakeup(sc);
Sujithf83da962009-07-23 15:32:37 +05301867 ath_tx_aggr_stop(sc, sta, tid);
Felix Fietkau08c96ab2013-05-18 21:28:15 +02001868 if (!flush)
Felix Fietkau16e23422013-05-17 12:58:24 +02001869 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001870 ath9k_ps_restore(sc);
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001871 break;
Johannes Bergb1720232009-03-23 17:28:39 +01001872 case IEEE80211_AMPDU_TX_OPERATIONAL:
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001873 ath9k_ps_wakeup(sc);
Sujith8469cde2008-10-29 10:19:28 +05301874 ath_tx_aggr_resume(sc, sta, tid);
Luis R. Rodriguez8b685ba2009-12-23 20:03:29 -05001875 ath9k_ps_restore(sc);
Sujith8469cde2008-10-29 10:19:28 +05301876 break;
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001877 default:
Joe Perches38002762010-12-02 19:12:36 -08001878 ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001879 }
1880
Sujith Manoharan7ca7c772013-05-08 05:03:32 +05301881 mutex_unlock(&sc->mutex);
Johannes Berg85ad1812010-06-10 10:21:49 +02001882
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07001883 return ret;
1884}
1885
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001886static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
1887 struct survey_info *survey)
1888{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001889 struct ath_softc *sc = hw->priv;
Felix Fietkau34300982010-10-10 18:21:52 +02001890 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau39162db2010-09-29 19:12:06 +02001891 struct ieee80211_supported_band *sband;
Felix Fietkau34300982010-10-10 18:21:52 +02001892 struct ieee80211_channel *chan;
Felix Fietkau34300982010-10-10 18:21:52 +02001893 int pos;
1894
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001895 if (config_enabled(CONFIG_ATH9K_TX99))
1896 return -EOPNOTSUPP;
1897
Sujith Manoharanb7cc9b92013-12-26 08:14:40 +05301898 spin_lock_bh(&common->cc_lock);
Felix Fietkau34300982010-10-10 18:21:52 +02001899 if (idx == 0)
1900 ath_update_survey_stats(sc);
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001901
Felix Fietkau39162db2010-09-29 19:12:06 +02001902 sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ];
1903 if (sband && idx >= sband->n_channels) {
1904 idx -= sband->n_channels;
1905 sband = NULL;
1906 }
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001907
Felix Fietkau39162db2010-09-29 19:12:06 +02001908 if (!sband)
1909 sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ];
1910
Felix Fietkau34300982010-10-10 18:21:52 +02001911 if (!sband || idx >= sband->n_channels) {
Sujith Manoharanb7cc9b92013-12-26 08:14:40 +05301912 spin_unlock_bh(&common->cc_lock);
Felix Fietkau34300982010-10-10 18:21:52 +02001913 return -ENOENT;
Felix Fietkau4f1a5a42010-09-29 17:15:28 +02001914 }
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001915
Felix Fietkau34300982010-10-10 18:21:52 +02001916 chan = &sband->channels[idx];
1917 pos = chan->hw_value;
1918 memcpy(survey, &sc->survey[pos], sizeof(*survey));
1919 survey->channel = chan;
Sujith Manoharanb7cc9b92013-12-26 08:14:40 +05301920 spin_unlock_bh(&common->cc_lock);
Felix Fietkau34300982010-10-10 18:21:52 +02001921
Benoit Papillault62dad5b2010-04-28 00:08:24 +02001922 return 0;
1923}
1924
Lorenzo Bianconi24a19362014-09-16 02:13:15 +02001925static void ath9k_enable_dynack(struct ath_softc *sc)
1926{
1927#ifdef CONFIG_ATH9K_DYNACK
1928 u32 rfilt;
1929 struct ath_hw *ah = sc->sc_ah;
1930
1931 ath_dynack_reset(ah);
1932
1933 ah->dynack.enabled = true;
1934 rfilt = ath_calcrxfilter(sc);
1935 ath9k_hw_setrxfilter(ah, rfilt);
1936#endif
1937}
1938
Lorenzo Bianconia4bcaf52014-09-04 23:57:41 +02001939static void ath9k_set_coverage_class(struct ieee80211_hw *hw,
1940 s16 coverage_class)
Felix Fietkaue239d852010-01-15 02:34:58 +01001941{
Felix Fietkau9ac586152011-01-24 19:23:18 +01001942 struct ath_softc *sc = hw->priv;
Felix Fietkaue239d852010-01-15 02:34:58 +01001943 struct ath_hw *ah = sc->sc_ah;
1944
Luis R. Rodriguez89f927a2013-10-14 17:42:11 -07001945 if (config_enabled(CONFIG_ATH9K_TX99))
1946 return;
1947
Felix Fietkaue239d852010-01-15 02:34:58 +01001948 mutex_lock(&sc->mutex);
Mohammed Shafi Shajakhan8b2a38272011-08-24 21:38:07 +05301949
Lorenzo Bianconi24a19362014-09-16 02:13:15 +02001950 if (coverage_class >= 0) {
1951 ah->coverage_class = coverage_class;
1952 if (ah->dynack.enabled) {
1953 u32 rfilt;
1954
1955 ah->dynack.enabled = false;
1956 rfilt = ath_calcrxfilter(sc);
1957 ath9k_hw_setrxfilter(ah, rfilt);
1958 }
1959 ath9k_ps_wakeup(sc);
1960 ath9k_hw_init_global_settings(ah);
1961 ath9k_ps_restore(sc);
1962 } else if (!ah->dynack.enabled) {
1963 ath9k_enable_dynack(sc);
1964 }
Mohammed Shafi Shajakhan8b2a38272011-08-24 21:38:07 +05301965
Felix Fietkaue239d852010-01-15 02:34:58 +01001966 mutex_unlock(&sc->mutex);
1967}
1968
Felix Fietkau10e23182013-11-11 22:23:35 +01001969static bool ath9k_has_tx_pending(struct ath_softc *sc)
1970{
Geert Uytterhoevenf7838072014-01-26 11:53:21 +01001971 int i, npend = 0;
Felix Fietkau10e23182013-11-11 22:23:35 +01001972
1973 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
1974 if (!ATH_TXQ_SETUP(sc, i))
1975 continue;
1976
Felix Fietkau10e23182013-11-11 22:23:35 +01001977 npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
1978 if (npend)
1979 break;
1980 }
1981
1982 return !!npend;
1983}
1984
Emmanuel Grumbach77be2c52014-03-27 11:30:29 +02001985static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1986 u32 queues, bool drop)
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001987{
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08001988 struct ath_softc *sc = hw->priv;
Felix Fietkaubff11762014-06-11 16:17:52 +05301989
1990 mutex_lock(&sc->mutex);
1991 __ath9k_flush(hw, queues, drop);
1992 mutex_unlock(&sc->mutex);
1993}
1994
1995void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
1996{
1997 struct ath_softc *sc = hw->priv;
Mohammed Shafi Shajakhan99aa55b2011-05-06 20:43:11 +05301998 struct ath_hw *ah = sc->sc_ah;
1999 struct ath_common *common = ath9k_hw_common(ah);
Felix Fietkau10e23182013-11-11 22:23:35 +01002000 int timeout = HZ / 5; /* 200 ms */
Rajkumar Manoharan2f6fc352011-04-28 15:31:57 +05302001 bool drain_txq;
Rajkumar Manoharan3ad9c382014-06-11 16:18:15 +05302002 int i;
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08002003
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08002004 cancel_delayed_work_sync(&sc->tx_complete_work);
2005
Mohammed Shafi Shajakhan6a6b3f32011-09-09 10:41:08 +05302006 if (ah->ah_flags & AH_UNPLUGGED) {
Joe Perchesd2182b62011-12-15 14:55:53 -08002007 ath_dbg(common, ANY, "Device has been unplugged!\n");
Mohammed Shafi Shajakhan6a6b3f32011-09-09 10:41:08 +05302008 return;
2009 }
2010
Oleksij Rempeleefa01d2014-02-27 11:40:46 +01002011 if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
Joe Perchesd2182b62011-12-15 14:55:53 -08002012 ath_dbg(common, ANY, "Device not present\n");
Mohammed Shafi Shajakhan99aa55b2011-05-06 20:43:11 +05302013 return;
2014 }
2015
Felix Fietkau10e23182013-11-11 22:23:35 +01002016 if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc),
2017 timeout) > 0)
2018 drop = false;
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08002019
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01002020 if (drop) {
2021 ath9k_ps_wakeup(sc);
2022 spin_lock_bh(&sc->sc_pcu_lock);
Felix Fietkau13815592013-01-20 18:51:53 +01002023 drain_txq = ath_drain_all_txq(sc);
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01002024 spin_unlock_bh(&sc->sc_pcu_lock);
Felix Fietkau9adcf442011-09-03 01:40:26 +02002025
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01002026 if (!drain_txq)
Felix Fietkau13815592013-01-20 18:51:53 +01002027 ath_reset(sc);
Felix Fietkau9adcf442011-09-03 01:40:26 +02002028
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01002029 ath9k_ps_restore(sc);
Rajkumar Manoharan3ad9c382014-06-11 16:18:15 +05302030 for (i = 0; i < IEEE80211_NUM_ACS; i++) {
2031 ieee80211_wake_queue(sc->hw,
2032 sc->cur_chan->hw_queue_base + i);
2033 }
Felix Fietkau9df0d6a2011-11-16 13:08:42 +01002034 }
Senthil Balasubramaniand78f4b32011-03-23 23:07:22 +05302035
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08002036 ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08002037}
2038
Vivek Natarajan15b91e82011-04-06 11:41:11 +05302039static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
2040{
2041 struct ath_softc *sc = hw->priv;
Vivek Natarajan15b91e82011-04-06 11:41:11 +05302042
Sujith Manoharan60913f42014-10-02 06:33:15 +05302043 return ath9k_has_tx_pending(sc);
Vivek Natarajan15b91e82011-04-06 11:41:11 +05302044}
2045
Mohammed Shafi Shajakhan5595f112011-05-19 18:08:57 +05302046static int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
Felix Fietkauba4903f2011-05-17 21:09:54 +02002047{
2048 struct ath_softc *sc = hw->priv;
2049 struct ath_hw *ah = sc->sc_ah;
2050 struct ieee80211_vif *vif;
2051 struct ath_vif *avp;
2052 struct ath_buf *bf;
2053 struct ath_tx_status ts;
Felix Fietkau4286df62012-02-27 19:58:40 +01002054 bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
Felix Fietkauba4903f2011-05-17 21:09:54 +02002055 int status;
2056
2057 vif = sc->beacon.bslot[0];
2058 if (!vif)
2059 return 0;
2060
Sujith Manoharanaa45fe92012-07-17 17:16:03 +05302061 if (!vif->bss_conf.enable_beacon)
Felix Fietkauba4903f2011-05-17 21:09:54 +02002062 return 0;
2063
Sujith Manoharanaa45fe92012-07-17 17:16:03 +05302064 avp = (void *)vif->drv_priv;
2065
Felix Fietkau4286df62012-02-27 19:58:40 +01002066 if (!sc->beacon.tx_processed && !edma) {
Felix Fietkauba4903f2011-05-17 21:09:54 +02002067 tasklet_disable(&sc->bcon_tasklet);
2068
2069 bf = avp->av_bcbuf;
2070 if (!bf || !bf->bf_mpdu)
2071 goto skip;
2072
2073 status = ath9k_hw_txprocdesc(ah, bf->bf_desc, &ts);
2074 if (status == -EINPROGRESS)
2075 goto skip;
2076
2077 sc->beacon.tx_processed = true;
2078 sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
2079
2080skip:
2081 tasklet_enable(&sc->bcon_tasklet);
2082 }
2083
2084 return sc->beacon.tx_last;
2085}
2086
Mohammed Shafi Shajakhan52c94f42011-08-20 17:21:42 +05302087static int ath9k_get_stats(struct ieee80211_hw *hw,
2088 struct ieee80211_low_level_stats *stats)
2089{
2090 struct ath_softc *sc = hw->priv;
2091 struct ath_hw *ah = sc->sc_ah;
2092 struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats;
2093
2094 stats->dot11ACKFailureCount = mib_stats->ackrcv_bad;
2095 stats->dot11RTSFailureCount = mib_stats->rts_bad;
2096 stats->dot11FCSErrorCount = mib_stats->fcs_bad;
2097 stats->dot11RTSSuccessCount = mib_stats->rts_good;
2098 return 0;
2099}
2100
Felix Fietkau43c35282011-09-03 01:40:27 +02002101static u32 fill_chainmask(u32 cap, u32 new)
2102{
2103 u32 filled = 0;
2104 int i;
2105
2106 for (i = 0; cap && new; i++, cap >>= 1) {
2107 if (!(cap & BIT(0)))
2108 continue;
2109
2110 if (new & BIT(0))
2111 filled |= BIT(i);
2112
2113 new >>= 1;
2114 }
2115
2116 return filled;
2117}
2118
Felix Fietkau5d9c7e32012-07-15 19:53:30 +02002119static bool validate_antenna_mask(struct ath_hw *ah, u32 val)
2120{
Felix Fietkaufea92cb2013-01-20 21:55:22 +01002121 if (AR_SREV_9300_20_OR_LATER(ah))
2122 return true;
2123
Felix Fietkau5d9c7e32012-07-15 19:53:30 +02002124 switch (val & 0x7) {
2125 case 0x1:
2126 case 0x3:
2127 case 0x7:
2128 return true;
2129 case 0x2:
2130 return (ah->caps.rx_chainmask == 1);
2131 default:
2132 return false;
2133 }
2134}
2135
Felix Fietkau43c35282011-09-03 01:40:27 +02002136static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
2137{
2138 struct ath_softc *sc = hw->priv;
2139 struct ath_hw *ah = sc->sc_ah;
2140
Felix Fietkau5d9c7e32012-07-15 19:53:30 +02002141 if (ah->caps.rx_chainmask != 1)
2142 rx_ant |= tx_ant;
2143
2144 if (!validate_antenna_mask(ah, rx_ant) || !tx_ant)
Felix Fietkau43c35282011-09-03 01:40:27 +02002145 return -EINVAL;
2146
2147 sc->ant_rx = rx_ant;
2148 sc->ant_tx = tx_ant;
2149
2150 if (ah->caps.rx_chainmask == 1)
2151 return 0;
2152
2153 /* AR9100 runs into calibration issues if not all rx chains are enabled */
2154 if (AR_SREV_9100(ah))
2155 ah->rxchainmask = 0x7;
2156 else
2157 ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);
2158
2159 ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant);
Oleksij Rempelb57ba3b2014-02-25 14:48:55 +01002160 ath9k_cmn_reload_chainmask(ah);
Felix Fietkau43c35282011-09-03 01:40:27 +02002161
2162 return 0;
2163}
2164
2165static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
2166{
2167 struct ath_softc *sc = hw->priv;
2168
2169 *tx_ant = sc->ant_tx;
2170 *rx_ant = sc->ant_rx;
2171 return 0;
2172}
2173
Simon Wunderliche93d0832013-01-08 14:48:58 +01002174static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
2175{
2176 struct ath_softc *sc = hw->priv;
Oleksij Rempeleefa01d2014-02-27 11:40:46 +01002177 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2178 set_bit(ATH_OP_SCANNING, &common->op_flags);
Simon Wunderliche93d0832013-01-08 14:48:58 +01002179}
2180
2181static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
2182{
2183 struct ath_softc *sc = hw->priv;
Oleksij Rempeleefa01d2014-02-27 11:40:46 +01002184 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2185 clear_bit(ATH_OP_SCANNING, &common->op_flags);
Simon Wunderliche93d0832013-01-08 14:48:58 +01002186}
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302187
Sujith Manoharan499afac2014-08-22 20:39:31 +05302188#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
2189
Felix Fietkau78b21942014-06-11 16:17:55 +05302190static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
John W. Linville855df362014-06-25 15:15:14 -04002191 struct ieee80211_scan_request *hw_req)
Felix Fietkau78b21942014-06-11 16:17:55 +05302192{
John W. Linville855df362014-06-25 15:15:14 -04002193 struct cfg80211_scan_request *req = &hw_req->req;
Felix Fietkau78b21942014-06-11 16:17:55 +05302194 struct ath_softc *sc = hw->priv;
2195 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2196 int ret = 0;
2197
2198 mutex_lock(&sc->mutex);
2199
2200 if (WARN_ON(sc->offchannel.scan_req)) {
2201 ret = -EBUSY;
2202 goto out;
2203 }
2204
2205 ath9k_ps_wakeup(sc);
2206 set_bit(ATH_OP_SCANNING, &common->op_flags);
2207 sc->offchannel.scan_vif = vif;
2208 sc->offchannel.scan_req = req;
2209 sc->offchannel.scan_idx = 0;
Felix Fietkau78b21942014-06-11 16:17:55 +05302210
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302211 ath_dbg(common, CHAN_CTX, "HW scan request received on vif: %pM\n",
2212 vif->addr);
2213
2214 if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) {
2215 ath_dbg(common, CHAN_CTX, "Starting HW scan\n");
Felix Fietkau405393c2014-06-11 16:17:56 +05302216 ath_offchannel_next(sc);
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302217 }
Felix Fietkau78b21942014-06-11 16:17:55 +05302218
2219out:
2220 mutex_unlock(&sc->mutex);
2221
2222 return ret;
2223}
2224
2225static void ath9k_cancel_hw_scan(struct ieee80211_hw *hw,
2226 struct ieee80211_vif *vif)
2227{
2228 struct ath_softc *sc = hw->priv;
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302229 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2230
2231 ath_dbg(common, CHAN_CTX, "Cancel HW scan on vif: %pM\n", vif->addr);
Felix Fietkau78b21942014-06-11 16:17:55 +05302232
2233 mutex_lock(&sc->mutex);
2234 del_timer_sync(&sc->offchannel.timer);
2235 ath_scan_complete(sc, true);
2236 mutex_unlock(&sc->mutex);
2237}
2238
Felix Fietkau405393c2014-06-11 16:17:56 +05302239static int ath9k_remain_on_channel(struct ieee80211_hw *hw,
2240 struct ieee80211_vif *vif,
2241 struct ieee80211_channel *chan, int duration,
2242 enum ieee80211_roc_type type)
2243{
2244 struct ath_softc *sc = hw->priv;
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302245 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau405393c2014-06-11 16:17:56 +05302246 int ret = 0;
2247
2248 mutex_lock(&sc->mutex);
2249
2250 if (WARN_ON(sc->offchannel.roc_vif)) {
2251 ret = -EBUSY;
2252 goto out;
2253 }
2254
2255 ath9k_ps_wakeup(sc);
2256 sc->offchannel.roc_vif = vif;
2257 sc->offchannel.roc_chan = chan;
2258 sc->offchannel.roc_duration = duration;
2259
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302260 ath_dbg(common, CHAN_CTX,
2261 "RoC request on vif: %pM, type: %d duration: %d\n",
2262 vif->addr, type, duration);
2263
2264 if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) {
2265 ath_dbg(common, CHAN_CTX, "Starting RoC period\n");
Felix Fietkau405393c2014-06-11 16:17:56 +05302266 ath_offchannel_next(sc);
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302267 }
Felix Fietkau405393c2014-06-11 16:17:56 +05302268
2269out:
2270 mutex_unlock(&sc->mutex);
2271
2272 return ret;
2273}
2274
2275static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw)
2276{
2277 struct ath_softc *sc = hw->priv;
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302278 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau405393c2014-06-11 16:17:56 +05302279
2280 mutex_lock(&sc->mutex);
2281
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302282 ath_dbg(common, CHAN_CTX, "Cancel RoC\n");
Felix Fietkau405393c2014-06-11 16:17:56 +05302283 del_timer_sync(&sc->offchannel.timer);
2284
2285 if (sc->offchannel.roc_vif) {
2286 if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START)
2287 ath_roc_complete(sc, true);
2288 }
2289
2290 mutex_unlock(&sc->mutex);
2291
2292 return 0;
2293}
2294
Felix Fietkau39305632014-06-11 16:17:57 +05302295static int ath9k_add_chanctx(struct ieee80211_hw *hw,
2296 struct ieee80211_chanctx_conf *conf)
2297{
2298 struct ath_softc *sc = hw->priv;
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302299 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau39305632014-06-11 16:17:57 +05302300 struct ath_chanctx *ctx, **ptr;
Rajkumar Manoharan3ad9c382014-06-11 16:18:15 +05302301 int pos;
Felix Fietkau39305632014-06-11 16:17:57 +05302302
2303 mutex_lock(&sc->mutex);
Rajkumar Manoharanc4dc0d02014-06-11 16:17:58 +05302304
2305 ath_for_each_chanctx(sc, ctx) {
2306 if (ctx->assigned)
2307 continue;
2308
2309 ptr = (void *) conf->drv_priv;
2310 *ptr = ctx;
2311 ctx->assigned = true;
Rajkumar Manoharan3ad9c382014-06-11 16:18:15 +05302312 pos = ctx - &sc->chanctx[0];
2313 ctx->hw_queue_base = pos * IEEE80211_NUM_ACS;
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302314
2315 ath_dbg(common, CHAN_CTX,
2316 "Add channel context: %d MHz\n",
2317 conf->def.chan->center_freq);
2318
Rajkumar Manoharanc4dc0d02014-06-11 16:17:58 +05302319 ath_chanctx_set_channel(sc, ctx, &conf->def);
Sujith Manoharan4c7e9ae2014-08-24 21:16:13 +05302320 ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ASSIGN);
2321
Felix Fietkau39305632014-06-11 16:17:57 +05302322 mutex_unlock(&sc->mutex);
Rajkumar Manoharanc4dc0d02014-06-11 16:17:58 +05302323 return 0;
Felix Fietkau39305632014-06-11 16:17:57 +05302324 }
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302325
Felix Fietkau39305632014-06-11 16:17:57 +05302326 mutex_unlock(&sc->mutex);
Rajkumar Manoharanc4dc0d02014-06-11 16:17:58 +05302327 return -ENOSPC;
Felix Fietkau39305632014-06-11 16:17:57 +05302328}
2329
2330
2331static void ath9k_remove_chanctx(struct ieee80211_hw *hw,
2332 struct ieee80211_chanctx_conf *conf)
2333{
2334 struct ath_softc *sc = hw->priv;
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302335 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau39305632014-06-11 16:17:57 +05302336 struct ath_chanctx *ctx = ath_chanctx_get(conf);
2337
2338 mutex_lock(&sc->mutex);
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302339
2340 ath_dbg(common, CHAN_CTX,
2341 "Remove channel context: %d MHz\n",
2342 conf->def.chan->center_freq);
2343
Felix Fietkau39305632014-06-11 16:17:57 +05302344 ctx->assigned = false;
Rajkumar Manoharan3ad9c382014-06-11 16:18:15 +05302345 ctx->hw_queue_base = -1;
Felix Fietkau73fa2f22014-06-11 16:18:10 +05302346 ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN);
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302347
Felix Fietkau39305632014-06-11 16:17:57 +05302348 mutex_unlock(&sc->mutex);
2349}
2350
2351static void ath9k_change_chanctx(struct ieee80211_hw *hw,
2352 struct ieee80211_chanctx_conf *conf,
2353 u32 changed)
2354{
2355 struct ath_softc *sc = hw->priv;
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302356 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau39305632014-06-11 16:17:57 +05302357 struct ath_chanctx *ctx = ath_chanctx_get(conf);
2358
2359 mutex_lock(&sc->mutex);
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302360 ath_dbg(common, CHAN_CTX,
2361 "Change channel context: %d MHz\n",
2362 conf->def.chan->center_freq);
Felix Fietkau39305632014-06-11 16:17:57 +05302363 ath_chanctx_set_channel(sc, ctx, &conf->def);
2364 mutex_unlock(&sc->mutex);
2365}
2366
2367static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw,
2368 struct ieee80211_vif *vif,
2369 struct ieee80211_chanctx_conf *conf)
2370{
2371 struct ath_softc *sc = hw->priv;
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302372 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau39305632014-06-11 16:17:57 +05302373 struct ath_vif *avp = (void *)vif->drv_priv;
2374 struct ath_chanctx *ctx = ath_chanctx_get(conf);
Rajkumar Manoharan3ad9c382014-06-11 16:18:15 +05302375 int i;
Felix Fietkau39305632014-06-11 16:17:57 +05302376
2377 mutex_lock(&sc->mutex);
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302378
2379 ath_dbg(common, CHAN_CTX,
2380 "Assign VIF (addr: %pM, type: %d, p2p: %d) to channel context: %d MHz\n",
2381 vif->addr, vif->type, vif->p2p,
2382 conf->def.chan->center_freq);
2383
Felix Fietkau39305632014-06-11 16:17:57 +05302384 avp->chanctx = ctx;
Sujith Manoharan2ce73c02014-09-19 13:00:42 +05302385 ctx->nvifs_assigned++;
Felix Fietkau39305632014-06-11 16:17:57 +05302386 list_add_tail(&avp->list, &ctx->vifs);
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05302387 ath9k_calculate_summary_state(sc, ctx);
Rajkumar Manoharan3ad9c382014-06-11 16:18:15 +05302388 for (i = 0; i < IEEE80211_NUM_ACS; i++)
2389 vif->hw_queue[i] = ctx->hw_queue_base + i;
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302390
Felix Fietkau39305632014-06-11 16:17:57 +05302391 mutex_unlock(&sc->mutex);
2392
2393 return 0;
2394}
2395
2396static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw,
2397 struct ieee80211_vif *vif,
2398 struct ieee80211_chanctx_conf *conf)
2399{
2400 struct ath_softc *sc = hw->priv;
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302401 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Felix Fietkau39305632014-06-11 16:17:57 +05302402 struct ath_vif *avp = (void *)vif->drv_priv;
2403 struct ath_chanctx *ctx = ath_chanctx_get(conf);
Rajkumar Manoharan3ad9c382014-06-11 16:18:15 +05302404 int ac;
Felix Fietkau39305632014-06-11 16:17:57 +05302405
2406 mutex_lock(&sc->mutex);
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302407
2408 ath_dbg(common, CHAN_CTX,
2409 "Remove VIF (addr: %pM, type: %d, p2p: %d) from channel context: %d MHz\n",
2410 vif->addr, vif->type, vif->p2p,
2411 conf->def.chan->center_freq);
2412
Felix Fietkau39305632014-06-11 16:17:57 +05302413 avp->chanctx = NULL;
Sujith Manoharan2ce73c02014-09-19 13:00:42 +05302414 ctx->nvifs_assigned--;
Felix Fietkau39305632014-06-11 16:17:57 +05302415 list_del(&avp->list);
Rajkumar Manoharan9a9c4fb2014-06-11 16:18:03 +05302416 ath9k_calculate_summary_state(sc, ctx);
Rajkumar Manoharan3ad9c382014-06-11 16:18:15 +05302417 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
2418 vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE;
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302419
Felix Fietkau39305632014-06-11 16:17:57 +05302420 mutex_unlock(&sc->mutex);
2421}
2422
Sujith Manoharane20a8542014-08-23 13:29:09 +05302423static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
2424 struct ieee80211_vif *vif)
2425{
2426 struct ath_softc *sc = hw->priv;
2427 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
2428 struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
2429 bool changed = false;
2430
2431 if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
2432 return;
2433
2434 if (!avp->chanctx)
2435 return;
2436
2437 mutex_lock(&sc->mutex);
2438
2439 spin_lock_bh(&sc->chan_lock);
2440 if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
2441 sc->next_chan = avp->chanctx;
2442 changed = true;
2443 }
Sujith Manoharan878066e2014-08-27 12:07:24 +05302444 ath_dbg(common, CHAN_CTX,
2445 "%s: Set chanctx state to FORCE_ACTIVE, changed: %d\n",
2446 __func__, changed);
Sujith Manoharane20a8542014-08-23 13:29:09 +05302447 sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
2448 spin_unlock_bh(&sc->chan_lock);
2449
2450 if (changed)
2451 ath_chanctx_set_next(sc, true);
2452
2453 mutex_unlock(&sc->mutex);
2454}
2455
Felix Fietkau78b21942014-06-11 16:17:55 +05302456void ath9k_fill_chanctx_ops(void)
2457{
Sujith Manoharan499afac2014-08-22 20:39:31 +05302458 if (!ath9k_is_chanctx_enabled())
Felix Fietkau78b21942014-06-11 16:17:55 +05302459 return;
2460
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302461 ath9k_ops.hw_scan = ath9k_hw_scan;
2462 ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan;
2463 ath9k_ops.remain_on_channel = ath9k_remain_on_channel;
Felix Fietkau405393c2014-06-11 16:17:56 +05302464 ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel;
Sujith Manoharanbc81d432014-08-22 20:39:27 +05302465 ath9k_ops.add_chanctx = ath9k_add_chanctx;
2466 ath9k_ops.remove_chanctx = ath9k_remove_chanctx;
2467 ath9k_ops.change_chanctx = ath9k_change_chanctx;
2468 ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx;
2469 ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx;
Sujith Manoharane20a8542014-08-23 13:29:09 +05302470 ath9k_ops.mgd_prepare_tx = ath9k_mgd_prepare_tx;
Felix Fietkau78b21942014-06-11 16:17:55 +05302471}
2472
Sujith Manoharan499afac2014-08-22 20:39:31 +05302473#endif
2474
Gabor Juhos6baff7f2009-01-14 20:17:06 +01002475struct ieee80211_ops ath9k_ops = {
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002476 .tx = ath9k_tx,
2477 .start = ath9k_start,
2478 .stop = ath9k_stop,
2479 .add_interface = ath9k_add_interface,
Rajkumar Manoharan6b3b9912010-12-08 19:38:55 +05302480 .change_interface = ath9k_change_interface,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002481 .remove_interface = ath9k_remove_interface,
2482 .config = ath9k_config,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002483 .configure_filter = ath9k_configure_filter,
Johannes Berg4ca77862010-02-19 19:06:56 +01002484 .sta_add = ath9k_sta_add,
2485 .sta_remove = ath9k_sta_remove,
Felix Fietkau55195412011-04-17 23:28:09 +02002486 .sta_notify = ath9k_sta_notify,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002487 .conf_tx = ath9k_conf_tx,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002488 .bss_info_changed = ath9k_bss_info_changed,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002489 .set_key = ath9k_set_key,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002490 .get_tsf = ath9k_get_tsf,
Alina Friedrichsen3b5d6652009-01-24 07:09:59 +01002491 .set_tsf = ath9k_set_tsf,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002492 .reset_tsf = ath9k_reset_tsf,
Johannes Berg4233df62008-10-13 13:35:05 +02002493 .ampdu_action = ath9k_ampdu_action,
Benoit Papillault62dad5b2010-04-28 00:08:24 +02002494 .get_survey = ath9k_get_survey,
Johannes Berg3b319aa2009-06-13 14:50:26 +05302495 .rfkill_poll = ath9k_rfkill_poll_state,
Felix Fietkaue239d852010-01-15 02:34:58 +01002496 .set_coverage_class = ath9k_set_coverage_class,
Vasanthakumar Thiagarajan69081622011-02-19 01:13:42 -08002497 .flush = ath9k_flush,
Vivek Natarajan15b91e82011-04-06 11:41:11 +05302498 .tx_frames_pending = ath9k_tx_frames_pending,
Mohammed Shafi Shajakhan52c94f42011-08-20 17:21:42 +05302499 .tx_last_beacon = ath9k_tx_last_beacon,
Felix Fietkau86a22ac2013-06-07 18:12:01 +02002500 .release_buffered_frames = ath9k_release_buffered_frames,
Mohammed Shafi Shajakhan52c94f42011-08-20 17:21:42 +05302501 .get_stats = ath9k_get_stats,
Felix Fietkau43c35282011-09-03 01:40:27 +02002502 .set_antenna = ath9k_set_antenna,
2503 .get_antenna = ath9k_get_antenna,
Ben Greearb90bd9d2012-05-15 15:33:25 -07002504
Sujith Manoharane60001e2013-10-28 12:22:04 +05302505#ifdef CONFIG_ATH9K_WOW
Mohammed Shafi Shajakhanb11e6402012-07-10 14:56:52 +05302506 .suspend = ath9k_suspend,
2507 .resume = ath9k_resume,
2508 .set_wakeup = ath9k_set_wakeup,
2509#endif
2510
Ben Greearb90bd9d2012-05-15 15:33:25 -07002511#ifdef CONFIG_ATH9K_DEBUGFS
2512 .get_et_sset_count = ath9k_get_et_sset_count,
Sujith Manoharana145daf2012-11-28 15:08:54 +05302513 .get_et_stats = ath9k_get_et_stats,
2514 .get_et_strings = ath9k_get_et_strings,
2515#endif
2516
Sujith Manoharan1cdbaf02014-01-13 07:29:27 +05302517#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_STATION_STATISTICS)
Sujith Manoharana145daf2012-11-28 15:08:54 +05302518 .sta_add_debugfs = ath9k_sta_add_debugfs,
Ben Greearb90bd9d2012-05-15 15:33:25 -07002519#endif
Simon Wunderliche93d0832013-01-08 14:48:58 +01002520 .sw_scan_start = ath9k_sw_scan_start,
2521 .sw_scan_complete = ath9k_sw_scan_complete,
Luis R. Rodriguezf078f202008-08-04 00:16:41 -07002522};