blob: c9254a61ca52d0984c23efdf4cb01aeb6b40ae23 [file] [log] [blame]
Sujithfb9987d2010-03-17 14:25:25 +05301/*
Sujith Manoharan5b681382011-05-17 13:36:18 +05302 * Copyright (c) 2010-2011 Atheros Communications Inc.
Sujithfb9987d2010-03-17 14:25:25 +05303 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "htc.h"
18
Sujithfb9987d2010-03-17 14:25:25 +053019/*************/
20/* Utilities */
21/*************/
22
Sujithfb9987d2010-03-17 14:25:25 +053023/* HACK Alert: Use 11NG for 2.4, use 11NA for 5 */
24static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
25 struct ath9k_channel *ichan)
26{
Felix Fietkau88969342013-10-11 23:30:53 +020027 if (IS_CHAN_5GHZ(ichan))
28 return HTC_MODE_11NA;
Sujithfb9987d2010-03-17 14:25:25 +053029
Felix Fietkau88969342013-10-11 23:30:53 +020030 return HTC_MODE_11NG;
Sujithfb9987d2010-03-17 14:25:25 +053031}
32
Sujith Manoharanf933ebe2010-12-01 12:30:27 +053033bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
34 enum ath9k_power_mode mode)
Vivek Natarajanbde748a2010-04-05 14:48:05 +053035{
36 bool ret;
37
38 mutex_lock(&priv->htc_pm_lock);
39 ret = ath9k_hw_setpower(priv->ah, mode);
40 mutex_unlock(&priv->htc_pm_lock);
41
42 return ret;
43}
44
45void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv)
46{
47 mutex_lock(&priv->htc_pm_lock);
48 if (++priv->ps_usecount != 1)
49 goto unlock;
50 ath9k_hw_setpower(priv->ah, ATH9K_PM_AWAKE);
51
52unlock:
53 mutex_unlock(&priv->htc_pm_lock);
54}
55
56void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv)
57{
Sujith Manoharan6bcfe672012-06-25 13:54:49 +053058 bool reset;
59
Vivek Natarajanbde748a2010-04-05 14:48:05 +053060 mutex_lock(&priv->htc_pm_lock);
61 if (--priv->ps_usecount != 0)
62 goto unlock;
63
Sujith Manoharan6bcfe672012-06-25 13:54:49 +053064 if (priv->ps_idle) {
65 ath9k_hw_setrxabort(priv->ah, true);
66 ath9k_hw_stopdmarecv(priv->ah, &reset);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +053067 ath9k_hw_setpower(priv->ah, ATH9K_PM_FULL_SLEEP);
Sujith Manoharan6bcfe672012-06-25 13:54:49 +053068 } else if (priv->ps_enabled) {
Vivek Natarajanbde748a2010-04-05 14:48:05 +053069 ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP);
Sujith Manoharan6bcfe672012-06-25 13:54:49 +053070 }
Vivek Natarajan8a8572a2010-04-27 13:05:37 +053071
Vivek Natarajanbde748a2010-04-05 14:48:05 +053072unlock:
73 mutex_unlock(&priv->htc_pm_lock);
74}
75
76void ath9k_ps_work(struct work_struct *work)
77{
78 struct ath9k_htc_priv *priv =
79 container_of(work, struct ath9k_htc_priv,
80 ps_work);
81 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
82
83 /* The chip wakes up after receiving the first beacon
84 while network sleep is enabled. For the driver to
85 be in sync with the hw, set the chip to awake and
86 only then set it to sleep.
87 */
88 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
89}
90
Sujith Manoharan7c277342011-02-21 07:48:39 +053091static void ath9k_htc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
92{
93 struct ath9k_htc_priv *priv = data;
94 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
95
Javier Cardona594e65b2013-05-08 10:16:46 -070096 if ((vif->type == NL80211_IFTYPE_AP ||
97 vif->type == NL80211_IFTYPE_MESH_POINT) &&
98 bss_conf->enable_beacon)
Sujith Manoharana5fae372011-02-21 07:49:53 +053099 priv->reconfig_beacon = true;
100
Sujith Manoharan7c277342011-02-21 07:48:39 +0530101 if (bss_conf->assoc) {
102 priv->rearm_ani = true;
103 priv->reconfig_beacon = true;
104 }
105}
106
107static void ath9k_htc_vif_reconfig(struct ath9k_htc_priv *priv)
108{
109 priv->rearm_ani = false;
110 priv->reconfig_beacon = false;
111
Johannes Berg8b2c9822012-11-06 20:23:30 +0100112 ieee80211_iterate_active_interfaces_atomic(
113 priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
114 ath9k_htc_vif_iter, priv);
Sujith Manoharan7c277342011-02-21 07:48:39 +0530115 if (priv->rearm_ani)
Sujith Manoharana2362542011-02-21 07:49:38 +0530116 ath9k_htc_start_ani(priv);
Sujith Manoharan7c277342011-02-21 07:48:39 +0530117
118 if (priv->reconfig_beacon) {
119 ath9k_htc_ps_wakeup(priv);
120 ath9k_htc_beacon_reconfig(priv);
121 ath9k_htc_ps_restore(priv);
122 }
123}
124
Sujith Manoharan585895c2011-02-21 07:48:46 +0530125static void ath9k_htc_bssid_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
126{
127 struct ath9k_vif_iter_data *iter_data = data;
128 int i;
129
Mathy Vanhoef657eb172013-11-28 12:21:45 +0100130 if (iter_data->hw_macaddr != NULL) {
131 for (i = 0; i < ETH_ALEN; i++)
132 iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
133 } else {
134 iter_data->hw_macaddr = mac;
135 }
Sujith Manoharan585895c2011-02-21 07:48:46 +0530136}
137
Mathy Vanhoef657eb172013-11-28 12:21:45 +0100138static void ath9k_htc_set_mac_bssid_mask(struct ath9k_htc_priv *priv,
Sujith Manoharan585895c2011-02-21 07:48:46 +0530139 struct ieee80211_vif *vif)
140{
141 struct ath_common *common = ath9k_hw_common(priv->ah);
142 struct ath9k_vif_iter_data iter_data;
143
144 /*
Mathy Vanhoef657eb172013-11-28 12:21:45 +0100145 * Pick the MAC address of the first interface as the new hardware
146 * MAC address. The hardware will use it together with the BSSID mask
147 * when matching addresses.
Sujith Manoharan585895c2011-02-21 07:48:46 +0530148 */
Mathy Vanhoef657eb172013-11-28 12:21:45 +0100149 iter_data.hw_macaddr = NULL;
Sujith Manoharan585895c2011-02-21 07:48:46 +0530150 memset(&iter_data.mask, 0xff, ETH_ALEN);
151
152 if (vif)
153 ath9k_htc_bssid_iter(&iter_data, vif->addr, vif);
154
155 /* Get list of all active MAC addresses */
Johannes Berg8b2c9822012-11-06 20:23:30 +0100156 ieee80211_iterate_active_interfaces_atomic(
157 priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
158 ath9k_htc_bssid_iter, &iter_data);
Sujith Manoharan585895c2011-02-21 07:48:46 +0530159
160 memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
Mathy Vanhoef657eb172013-11-28 12:21:45 +0100161
162 if (iter_data.hw_macaddr)
163 memcpy(common->macaddr, iter_data.hw_macaddr, ETH_ALEN);
164
Sujith Manoharan585895c2011-02-21 07:48:46 +0530165 ath_hw_setbssidmask(common);
166}
167
Sujith Manoharanffbe7c82011-02-21 07:49:31 +0530168static void ath9k_htc_set_opmode(struct ath9k_htc_priv *priv)
169{
170 if (priv->num_ibss_vif)
171 priv->ah->opmode = NL80211_IFTYPE_ADHOC;
172 else if (priv->num_ap_vif)
173 priv->ah->opmode = NL80211_IFTYPE_AP;
Javier Cardona594e65b2013-05-08 10:16:46 -0700174 else if (priv->num_mbss_vif)
175 priv->ah->opmode = NL80211_IFTYPE_MESH_POINT;
Sujith Manoharanffbe7c82011-02-21 07:49:31 +0530176 else
177 priv->ah->opmode = NL80211_IFTYPE_STATION;
178
179 ath9k_hw_setopmode(priv->ah);
180}
181
Sujith Manoharan73908672010-12-28 14:28:27 +0530182void ath9k_htc_reset(struct ath9k_htc_priv *priv)
183{
184 struct ath_hw *ah = priv->ah;
185 struct ath_common *common = ath9k_hw_common(ah);
Karl Beldan675a0b02013-03-25 16:26:57 +0100186 struct ieee80211_channel *channel = priv->hw->conf.chandef.chan;
Rajkumar Manoharan4e3ae382011-01-15 01:33:28 +0530187 struct ath9k_hw_cal_data *caldata = NULL;
Sujith Manoharan73908672010-12-28 14:28:27 +0530188 enum htc_phymode mode;
189 __be16 htc_mode;
190 u8 cmd_rsp;
191 int ret;
192
193 mutex_lock(&priv->mutex);
194 ath9k_htc_ps_wakeup(priv);
195
Sujith Manoharana2362542011-02-21 07:49:38 +0530196 ath9k_htc_stop_ani(priv);
Sujith Manoharan73908672010-12-28 14:28:27 +0530197 ieee80211_stop_queues(priv->hw);
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530198
Sujith Manoharan859c3ca2011-04-13 11:26:39 +0530199 del_timer_sync(&priv->tx.cleanup_timer);
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530200 ath9k_htc_tx_drain(priv);
201
Sujith Manoharan73908672010-12-28 14:28:27 +0530202 WMI_CMD(WMI_DISABLE_INTR_CMDID);
203 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
204 WMI_CMD(WMI_STOP_RECV_CMDID);
205
Sujith Manoharanf4c88992011-04-13 11:23:52 +0530206 ath9k_wmi_event_drain(priv);
207
Rajkumar Manoharan4e3ae382011-01-15 01:33:28 +0530208 caldata = &priv->caldata;
Sujith Manoharan73908672010-12-28 14:28:27 +0530209 ret = ath9k_hw_reset(ah, ah->curchan, caldata, false);
210 if (ret) {
211 ath_err(common,
212 "Unable to reset device (%u Mhz) reset status %d\n",
213 channel->center_freq, ret);
214 }
215
Rajkumar Manoharanb2a5c3d2011-01-31 23:47:45 +0530216 ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit,
217 &priv->curtxpow);
Sujith Manoharan73908672010-12-28 14:28:27 +0530218
219 WMI_CMD(WMI_START_RECV_CMDID);
220 ath9k_host_rx_init(priv);
221
222 mode = ath9k_htc_get_curmode(priv, ah->curchan);
223 htc_mode = cpu_to_be16(mode);
224 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
225
226 WMI_CMD(WMI_ENABLE_INTR_CMDID);
227 htc_start(priv->htc);
Sujith Manoharan7c277342011-02-21 07:48:39 +0530228 ath9k_htc_vif_reconfig(priv);
Sujith Manoharan73908672010-12-28 14:28:27 +0530229 ieee80211_wake_queues(priv->hw);
230
Sujith Manoharan859c3ca2011-04-13 11:26:39 +0530231 mod_timer(&priv->tx.cleanup_timer,
232 jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
233
Sujith Manoharan73908672010-12-28 14:28:27 +0530234 ath9k_htc_ps_restore(priv);
235 mutex_unlock(&priv->mutex);
236}
237
Sujithfb9987d2010-03-17 14:25:25 +0530238static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
239 struct ieee80211_hw *hw,
240 struct ath9k_channel *hchan)
241{
242 struct ath_hw *ah = priv->ah;
243 struct ath_common *common = ath9k_hw_common(ah);
244 struct ieee80211_conf *conf = &common->hw->conf;
Sujith Manoharan039a0722010-12-28 14:28:37 +0530245 bool fastcc;
Karl Beldan675a0b02013-03-25 16:26:57 +0100246 struct ieee80211_channel *channel = hw->conf.chandef.chan;
Vivek Natarajan8354dd32011-02-18 16:09:51 +0530247 struct ath9k_hw_cal_data *caldata = NULL;
Sujithfb9987d2010-03-17 14:25:25 +0530248 enum htc_phymode mode;
Sujith7f1f5a02010-04-16 11:54:03 +0530249 __be16 htc_mode;
Sujithfb9987d2010-03-17 14:25:25 +0530250 u8 cmd_rsp;
251 int ret;
252
Sujith Manoharand8a2c512012-06-25 13:54:41 +0530253 if (test_bit(OP_INVALID, &priv->op_flags))
Sujithfb9987d2010-03-17 14:25:25 +0530254 return -EIO;
255
Sujith Manoharan039a0722010-12-28 14:28:37 +0530256 fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
Sujithfb9987d2010-03-17 14:25:25 +0530257
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530258 ath9k_htc_ps_wakeup(priv);
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530259
Sujith Manoharan859c3ca2011-04-13 11:26:39 +0530260 del_timer_sync(&priv->tx.cleanup_timer);
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530261 ath9k_htc_tx_drain(priv);
262
Sujithfb9987d2010-03-17 14:25:25 +0530263 WMI_CMD(WMI_DISABLE_INTR_CMDID);
264 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
265 WMI_CMD(WMI_STOP_RECV_CMDID);
266
Sujith Manoharanf4c88992011-04-13 11:23:52 +0530267 ath9k_wmi_event_drain(priv);
268
Joe Perchesd2182b62011-12-15 14:55:53 -0800269 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -0800270 "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n",
271 priv->ah->curchan->channel,
272 channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf),
273 fastcc);
Sujithfb9987d2010-03-17 14:25:25 +0530274
Rajkumar Manoharan4e3ae382011-01-15 01:33:28 +0530275 if (!fastcc)
276 caldata = &priv->caldata;
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530277
Felix Fietkau20bd2a02010-07-31 00:12:00 +0200278 ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
Sujithfb9987d2010-03-17 14:25:25 +0530279 if (ret) {
Joe Perches38002762010-12-02 19:12:36 -0800280 ath_err(common,
281 "Unable to reset channel (%u Mhz) reset status %d\n",
282 channel->center_freq, ret);
Sujithfb9987d2010-03-17 14:25:25 +0530283 goto err;
284 }
285
Rajkumar Manoharanb2a5c3d2011-01-31 23:47:45 +0530286 ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit,
287 &priv->curtxpow);
Sujithfb9987d2010-03-17 14:25:25 +0530288
289 WMI_CMD(WMI_START_RECV_CMDID);
290 if (ret)
291 goto err;
292
293 ath9k_host_rx_init(priv);
294
295 mode = ath9k_htc_get_curmode(priv, hchan);
296 htc_mode = cpu_to_be16(mode);
297 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
298 if (ret)
299 goto err;
300
301 WMI_CMD(WMI_ENABLE_INTR_CMDID);
302 if (ret)
303 goto err;
304
305 htc_start(priv->htc);
Sujith Manoharana5fae372011-02-21 07:49:53 +0530306
Sujith Manoharand8a2c512012-06-25 13:54:41 +0530307 if (!test_bit(OP_SCANNING, &priv->op_flags) &&
Sujith Manoharana5fae372011-02-21 07:49:53 +0530308 !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
309 ath9k_htc_vif_reconfig(priv);
310
Sujith Manoharan859c3ca2011-04-13 11:26:39 +0530311 mod_timer(&priv->tx.cleanup_timer,
312 jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
313
Sujithfb9987d2010-03-17 14:25:25 +0530314err:
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530315 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530316 return ret;
317}
318
Sujith Manoharana97b4782011-02-21 07:48:00 +0530319/*
320 * Monitor mode handling is a tad complicated because the firmware requires
321 * an interface to be created exclusively, while mac80211 doesn't associate
322 * an interface with the mode.
323 *
324 * So, for now, only one monitor interface can be configured.
325 */
Sujith Manoharancc721282011-01-03 21:22:18 +0530326static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
Rajkumar Manoharan81fc2a32010-11-26 23:24:33 +0530327{
328 struct ath_common *common = ath9k_hw_common(priv->ah);
329 struct ath9k_htc_target_vif hvif;
330 int ret = 0;
331 u8 cmd_rsp;
332
Sujith Manoharancc721282011-01-03 21:22:18 +0530333 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
334 memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
Sujith Manoharana97b4782011-02-21 07:48:00 +0530335 hvif.index = priv->mon_vif_idx;
Sujith Manoharancc721282011-01-03 21:22:18 +0530336 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
Sujith Manoharan0ff2b5c2011-04-20 11:00:34 +0530337 if (ret) {
338 ath_err(common, "Unable to remove monitor interface at idx: %d\n",
339 priv->mon_vif_idx);
340 }
341
Sujith Manoharancc721282011-01-03 21:22:18 +0530342 priv->nvifs--;
Sujith Manoharana97b4782011-02-21 07:48:00 +0530343 priv->vif_slot &= ~(1 << priv->mon_vif_idx);
Sujith Manoharancc721282011-01-03 21:22:18 +0530344}
345
346static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
347{
348 struct ath_common *common = ath9k_hw_common(priv->ah);
349 struct ath9k_htc_target_vif hvif;
350 struct ath9k_htc_target_sta tsta;
Sujith Manoharana97b4782011-02-21 07:48:00 +0530351 int ret = 0, sta_idx;
Sujith Manoharancc721282011-01-03 21:22:18 +0530352 u8 cmd_rsp;
353
Sujith Manoharana97b4782011-02-21 07:48:00 +0530354 if ((priv->nvifs >= ATH9K_HTC_MAX_VIF) ||
355 (priv->nstations >= ATH9K_HTC_MAX_STA)) {
356 ret = -ENOBUFS;
357 goto err_vif;
358 }
Rajkumar Manoharan81fc2a32010-11-26 23:24:33 +0530359
Sujith Manoharana97b4782011-02-21 07:48:00 +0530360 sta_idx = ffz(priv->sta_slot);
361 if ((sta_idx < 0) || (sta_idx > ATH9K_HTC_MAX_STA)) {
362 ret = -ENOBUFS;
363 goto err_vif;
364 }
Sujith Manoharancc721282011-01-03 21:22:18 +0530365
366 /*
367 * Add an interface.
368 */
Rajkumar Manoharan81fc2a32010-11-26 23:24:33 +0530369 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
370 memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
371
Sujith Manoharane4c62502011-04-13 11:24:43 +0530372 hvif.opmode = HTC_M_MONITOR;
Sujith Manoharana97b4782011-02-21 07:48:00 +0530373 hvif.index = ffz(priv->vif_slot);
Rajkumar Manoharan81fc2a32010-11-26 23:24:33 +0530374
375 WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
376 if (ret)
Sujith Manoharana97b4782011-02-21 07:48:00 +0530377 goto err_vif;
378
379 /*
380 * Assign the monitor interface index as a special case here.
381 * This is needed when the interface is brought down.
382 */
383 priv->mon_vif_idx = hvif.index;
384 priv->vif_slot |= (1 << hvif.index);
385
386 /*
387 * Set the hardware mode to monitor only if there are no
388 * other interfaces.
389 */
390 if (!priv->nvifs)
391 priv->ah->opmode = NL80211_IFTYPE_MONITOR;
Rajkumar Manoharan81fc2a32010-11-26 23:24:33 +0530392
393 priv->nvifs++;
Sujith Manoharancc721282011-01-03 21:22:18 +0530394
395 /*
396 * Associate a station with the interface for packet injection.
397 */
Sujith Manoharancc721282011-01-03 21:22:18 +0530398 memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta));
399
400 memcpy(&tsta.macaddr, common->macaddr, ETH_ALEN);
401
402 tsta.is_vif_sta = 1;
Sujith Manoharana97b4782011-02-21 07:48:00 +0530403 tsta.sta_index = sta_idx;
Sujith Manoharancc721282011-01-03 21:22:18 +0530404 tsta.vif_index = hvif.index;
Sujith Manoharanb97c57f2011-04-13 11:24:37 +0530405 tsta.maxampdu = cpu_to_be16(0xffff);
Sujith Manoharancc721282011-01-03 21:22:18 +0530406
407 WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
408 if (ret) {
409 ath_err(common, "Unable to add station entry for monitor mode\n");
Sujith Manoharana97b4782011-02-21 07:48:00 +0530410 goto err_sta;
Sujith Manoharancc721282011-01-03 21:22:18 +0530411 }
412
Sujith Manoharana97b4782011-02-21 07:48:00 +0530413 priv->sta_slot |= (1 << sta_idx);
Sujith Manoharancc721282011-01-03 21:22:18 +0530414 priv->nstations++;
Sujith Manoharana97b4782011-02-21 07:48:00 +0530415 priv->vif_sta_pos[priv->mon_vif_idx] = sta_idx;
Sujith Manoharan55de80d2011-01-05 01:06:21 +0530416 priv->ah->is_monitoring = true;
417
Joe Perchesd2182b62011-12-15 14:55:53 -0800418 ath_dbg(common, CONFIG,
Sujith Manoharana97b4782011-02-21 07:48:00 +0530419 "Attached a monitor interface at idx: %d, sta idx: %d\n",
420 priv->mon_vif_idx, sta_idx);
421
Rajkumar Manoharan81fc2a32010-11-26 23:24:33 +0530422 return 0;
Sujith Manoharancc721282011-01-03 21:22:18 +0530423
Sujith Manoharana97b4782011-02-21 07:48:00 +0530424err_sta:
Sujith Manoharancc721282011-01-03 21:22:18 +0530425 /*
426 * Remove the interface from the target.
427 */
428 __ath9k_htc_remove_monitor_interface(priv);
Sujith Manoharana97b4782011-02-21 07:48:00 +0530429err_vif:
Joe Perchesd2182b62011-12-15 14:55:53 -0800430 ath_dbg(common, FATAL, "Unable to attach a monitor interface\n");
Sujith Manoharana97b4782011-02-21 07:48:00 +0530431
Sujith Manoharancc721282011-01-03 21:22:18 +0530432 return ret;
Rajkumar Manoharan81fc2a32010-11-26 23:24:33 +0530433}
434
435static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
436{
437 struct ath_common *common = ath9k_hw_common(priv->ah);
Rajkumar Manoharan81fc2a32010-11-26 23:24:33 +0530438 int ret = 0;
Sujith Manoharancc721282011-01-03 21:22:18 +0530439 u8 cmd_rsp, sta_idx;
Rajkumar Manoharan81fc2a32010-11-26 23:24:33 +0530440
Sujith Manoharancc721282011-01-03 21:22:18 +0530441 __ath9k_htc_remove_monitor_interface(priv);
Rajkumar Manoharan81fc2a32010-11-26 23:24:33 +0530442
Sujith Manoharana97b4782011-02-21 07:48:00 +0530443 sta_idx = priv->vif_sta_pos[priv->mon_vif_idx];
Sujith Manoharancc721282011-01-03 21:22:18 +0530444
445 WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx);
446 if (ret) {
447 ath_err(common, "Unable to remove station entry for monitor mode\n");
448 return ret;
449 }
450
Sujith Manoharana97b4782011-02-21 07:48:00 +0530451 priv->sta_slot &= ~(1 << sta_idx);
Sujith Manoharancc721282011-01-03 21:22:18 +0530452 priv->nstations--;
Sujith Manoharan55de80d2011-01-05 01:06:21 +0530453 priv->ah->is_monitoring = false;
Sujith Manoharancc721282011-01-03 21:22:18 +0530454
Joe Perchesd2182b62011-12-15 14:55:53 -0800455 ath_dbg(common, CONFIG,
Sujith Manoharana97b4782011-02-21 07:48:00 +0530456 "Removed a monitor interface at idx: %d, sta idx: %d\n",
457 priv->mon_vif_idx, sta_idx);
458
Sujith Manoharancc721282011-01-03 21:22:18 +0530459 return 0;
Rajkumar Manoharan81fc2a32010-11-26 23:24:33 +0530460}
461
Sujithfb9987d2010-03-17 14:25:25 +0530462static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
463 struct ieee80211_vif *vif,
464 struct ieee80211_sta *sta)
465{
466 struct ath_common *common = ath9k_hw_common(priv->ah);
467 struct ath9k_htc_target_sta tsta;
468 struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
469 struct ath9k_htc_sta *ista;
Sujith Manoharana97b4782011-02-21 07:48:00 +0530470 int ret, sta_idx;
Sujithfb9987d2010-03-17 14:25:25 +0530471 u8 cmd_rsp;
Sujith Manoharanf0dd4982011-04-20 11:01:00 +0530472 u16 maxampdu;
Sujithfb9987d2010-03-17 14:25:25 +0530473
474 if (priv->nstations >= ATH9K_HTC_MAX_STA)
475 return -ENOBUFS;
476
Sujith Manoharana97b4782011-02-21 07:48:00 +0530477 sta_idx = ffz(priv->sta_slot);
478 if ((sta_idx < 0) || (sta_idx > ATH9K_HTC_MAX_STA))
479 return -ENOBUFS;
480
Sujithfb9987d2010-03-17 14:25:25 +0530481 memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta));
482
483 if (sta) {
484 ista = (struct ath9k_htc_sta *) sta->drv_priv;
485 memcpy(&tsta.macaddr, sta->addr, ETH_ALEN);
486 memcpy(&tsta.bssid, common->curbssid, ETH_ALEN);
Sujith Manoharana97b4782011-02-21 07:48:00 +0530487 ista->index = sta_idx;
Mohammed Shafi Shajakhanfed27f62012-09-04 19:33:37 +0530488 tsta.is_vif_sta = 0;
489 maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
490 sta->ht_cap.ampdu_factor);
491 tsta.maxampdu = cpu_to_be16(maxampdu);
Sujithfb9987d2010-03-17 14:25:25 +0530492 } else {
493 memcpy(&tsta.macaddr, vif->addr, ETH_ALEN);
494 tsta.is_vif_sta = 1;
Mohammed Shafi Shajakhanfed27f62012-09-04 19:33:37 +0530495 tsta.maxampdu = cpu_to_be16(0xffff);
Sujithfb9987d2010-03-17 14:25:25 +0530496 }
497
Sujith Manoharana97b4782011-02-21 07:48:00 +0530498 tsta.sta_index = sta_idx;
Sujithfb9987d2010-03-17 14:25:25 +0530499 tsta.vif_index = avp->index;
Sujith Manoharanf0dd4982011-04-20 11:01:00 +0530500
Sujithfb9987d2010-03-17 14:25:25 +0530501 WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
502 if (ret) {
503 if (sta)
Joe Perches38002762010-12-02 19:12:36 -0800504 ath_err(common,
505 "Unable to add station entry for: %pM\n",
506 sta->addr);
Sujithfb9987d2010-03-17 14:25:25 +0530507 return ret;
508 }
509
Sujith Manoharana97b4782011-02-21 07:48:00 +0530510 if (sta) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800511 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -0800512 "Added a station entry for: %pM (idx: %d)\n",
513 sta->addr, tsta.sta_index);
Sujith Manoharana97b4782011-02-21 07:48:00 +0530514 } else {
Joe Perchesd2182b62011-12-15 14:55:53 -0800515 ath_dbg(common, CONFIG,
Sujith Manoharana97b4782011-02-21 07:48:00 +0530516 "Added a station entry for VIF %d (idx: %d)\n",
517 avp->index, tsta.sta_index);
518 }
Sujithfb9987d2010-03-17 14:25:25 +0530519
Sujith Manoharana97b4782011-02-21 07:48:00 +0530520 priv->sta_slot |= (1 << sta_idx);
Sujithfb9987d2010-03-17 14:25:25 +0530521 priv->nstations++;
Sujith Manoharana97b4782011-02-21 07:48:00 +0530522 if (!sta)
523 priv->vif_sta_pos[avp->index] = sta_idx;
524
Sujithfb9987d2010-03-17 14:25:25 +0530525 return 0;
526}
527
528static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
529 struct ieee80211_vif *vif,
530 struct ieee80211_sta *sta)
531{
532 struct ath_common *common = ath9k_hw_common(priv->ah);
Sujith Manoharana97b4782011-02-21 07:48:00 +0530533 struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
Sujithfb9987d2010-03-17 14:25:25 +0530534 struct ath9k_htc_sta *ista;
535 int ret;
536 u8 cmd_rsp, sta_idx;
537
538 if (sta) {
539 ista = (struct ath9k_htc_sta *) sta->drv_priv;
540 sta_idx = ista->index;
541 } else {
Sujith Manoharana97b4782011-02-21 07:48:00 +0530542 sta_idx = priv->vif_sta_pos[avp->index];
Sujithfb9987d2010-03-17 14:25:25 +0530543 }
544
545 WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx);
546 if (ret) {
547 if (sta)
Joe Perches38002762010-12-02 19:12:36 -0800548 ath_err(common,
549 "Unable to remove station entry for: %pM\n",
550 sta->addr);
Sujithfb9987d2010-03-17 14:25:25 +0530551 return ret;
552 }
553
Sujith Manoharana97b4782011-02-21 07:48:00 +0530554 if (sta) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800555 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -0800556 "Removed a station entry for: %pM (idx: %d)\n",
557 sta->addr, sta_idx);
Sujith Manoharana97b4782011-02-21 07:48:00 +0530558 } else {
Joe Perchesd2182b62011-12-15 14:55:53 -0800559 ath_dbg(common, CONFIG,
Sujith Manoharana97b4782011-02-21 07:48:00 +0530560 "Removed a station entry for VIF %d (idx: %d)\n",
561 avp->index, sta_idx);
562 }
Sujithfb9987d2010-03-17 14:25:25 +0530563
Sujith Manoharana97b4782011-02-21 07:48:00 +0530564 priv->sta_slot &= ~(1 << sta_idx);
Sujithfb9987d2010-03-17 14:25:25 +0530565 priv->nstations--;
Sujith Manoharana97b4782011-02-21 07:48:00 +0530566
Sujithfb9987d2010-03-17 14:25:25 +0530567 return 0;
568}
569
Sujith Manoharan3a0593e2011-04-20 14:33:28 +0530570int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv,
571 u8 enable_coex)
Sujithfb9987d2010-03-17 14:25:25 +0530572{
573 struct ath9k_htc_cap_target tcap;
574 int ret;
575 u8 cmd_rsp;
576
577 memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target));
578
Sujith Manoharan3a0593e2011-04-20 14:33:28 +0530579 tcap.ampdu_limit = cpu_to_be32(0xffff);
Sujith Manoharanbd548792011-05-17 12:42:14 +0530580 tcap.ampdu_subframes = 0xff;
Sujith Manoharan3a0593e2011-04-20 14:33:28 +0530581 tcap.enable_coex = enable_coex;
Sujith29d90752010-06-02 15:53:43 +0530582 tcap.tx_chainmask = priv->ah->caps.tx_chainmask;
Sujithfb9987d2010-03-17 14:25:25 +0530583
584 WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap);
585
586 return ret;
587}
588
Sujith0d425a72010-05-17 12:01:16 +0530589static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv,
590 struct ieee80211_sta *sta,
591 struct ath9k_htc_target_rate *trate)
Sujithfb9987d2010-03-17 14:25:25 +0530592{
Sujithfb9987d2010-03-17 14:25:25 +0530593 struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
594 struct ieee80211_supported_band *sband;
Sujithfb9987d2010-03-17 14:25:25 +0530595 u32 caps = 0;
Sujith0d425a72010-05-17 12:01:16 +0530596 int i, j;
Sujithfb9987d2010-03-17 14:25:25 +0530597
Karl Beldan675a0b02013-03-25 16:26:57 +0100598 sband = priv->hw->wiphy->bands[priv->hw->conf.chandef.chan->band];
Sujithfb9987d2010-03-17 14:25:25 +0530599
600 for (i = 0, j = 0; i < sband->n_bitrates; i++) {
601 if (sta->supp_rates[sband->band] & BIT(i)) {
Sujith0d425a72010-05-17 12:01:16 +0530602 trate->rates.legacy_rates.rs_rates[j]
Sujithfb9987d2010-03-17 14:25:25 +0530603 = (sband->bitrates[i].bitrate * 2) / 10;
604 j++;
605 }
606 }
Sujith0d425a72010-05-17 12:01:16 +0530607 trate->rates.legacy_rates.rs_nrates = j;
Sujithfb9987d2010-03-17 14:25:25 +0530608
609 if (sta->ht_cap.ht_supported) {
610 for (i = 0, j = 0; i < 77; i++) {
611 if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
Sujith0d425a72010-05-17 12:01:16 +0530612 trate->rates.ht_rates.rs_rates[j++] = i;
Sujithfb9987d2010-03-17 14:25:25 +0530613 if (j == ATH_HTC_RATE_MAX)
614 break;
615 }
Sujith0d425a72010-05-17 12:01:16 +0530616 trate->rates.ht_rates.rs_nrates = j;
Sujithfb9987d2010-03-17 14:25:25 +0530617
618 caps = WLAN_RC_HT_FLAG;
Oleksij Rempela226c3d2013-06-09 18:51:24 +0200619 if (sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
620 caps |= ATH_RC_TX_STBC_FLAG;
Felix Fietkau35537272010-06-12 17:22:33 +0200621 if (sta->ht_cap.mcs.rx_mask[1])
622 caps |= WLAN_RC_DS_FLAG;
Vivek Natarajan71ba1862010-08-12 14:23:28 +0530623 if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
624 (conf_is_ht40(&priv->hw->conf)))
Sujithfb9987d2010-03-17 14:25:25 +0530625 caps |= WLAN_RC_40_FLAG;
Sujithb4dec5e2010-05-17 12:01:19 +0530626 if (conf_is_ht40(&priv->hw->conf) &&
627 (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40))
Sujithfb9987d2010-03-17 14:25:25 +0530628 caps |= WLAN_RC_SGI_FLAG;
Sujithb4dec5e2010-05-17 12:01:19 +0530629 else if (conf_is_ht20(&priv->hw->conf) &&
630 (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20))
631 caps |= WLAN_RC_SGI_FLAG;
Sujithfb9987d2010-03-17 14:25:25 +0530632 }
633
Sujith0d425a72010-05-17 12:01:16 +0530634 trate->sta_index = ista->index;
635 trate->isnew = 1;
636 trate->capflags = cpu_to_be32(caps);
637}
Sujithfb9987d2010-03-17 14:25:25 +0530638
Sujith0d425a72010-05-17 12:01:16 +0530639static int ath9k_htc_send_rate_cmd(struct ath9k_htc_priv *priv,
640 struct ath9k_htc_target_rate *trate)
641{
642 struct ath_common *common = ath9k_hw_common(priv->ah);
643 int ret;
644 u8 cmd_rsp;
645
646 WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, trate);
Sujithfb9987d2010-03-17 14:25:25 +0530647 if (ret) {
Joe Perches38002762010-12-02 19:12:36 -0800648 ath_err(common,
649 "Unable to initialize Rate information on target\n");
Sujithfb9987d2010-03-17 14:25:25 +0530650 }
651
Sujith0d425a72010-05-17 12:01:16 +0530652 return ret;
Sujithfb9987d2010-03-17 14:25:25 +0530653}
654
Sujith0d425a72010-05-17 12:01:16 +0530655static void ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
656 struct ieee80211_sta *sta)
Sujithfb9987d2010-03-17 14:25:25 +0530657{
Sujithfb9987d2010-03-17 14:25:25 +0530658 struct ath_common *common = ath9k_hw_common(priv->ah);
Sujith0d425a72010-05-17 12:01:16 +0530659 struct ath9k_htc_target_rate trate;
Sujithfb9987d2010-03-17 14:25:25 +0530660 int ret;
Sujithfb9987d2010-03-17 14:25:25 +0530661
Sujith0d425a72010-05-17 12:01:16 +0530662 memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
663 ath9k_htc_setup_rate(priv, sta, &trate);
664 ret = ath9k_htc_send_rate_cmd(priv, &trate);
665 if (!ret)
Joe Perchesd2182b62011-12-15 14:55:53 -0800666 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -0800667 "Updated target sta: %pM, rate caps: 0x%X\n",
668 sta->addr, be32_to_cpu(trate.capflags));
Sujithfb9987d2010-03-17 14:25:25 +0530669}
670
Sujith2c76ef82010-05-17 12:01:18 +0530671static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv,
672 struct ieee80211_vif *vif,
673 struct ieee80211_bss_conf *bss_conf)
674{
675 struct ath_common *common = ath9k_hw_common(priv->ah);
676 struct ath9k_htc_target_rate trate;
677 struct ieee80211_sta *sta;
678 int ret;
679
680 memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
681
682 rcu_read_lock();
683 sta = ieee80211_find_sta(vif, bss_conf->bssid);
684 if (!sta) {
685 rcu_read_unlock();
686 return;
687 }
688 ath9k_htc_setup_rate(priv, sta, &trate);
689 rcu_read_unlock();
690
691 ret = ath9k_htc_send_rate_cmd(priv, &trate);
692 if (!ret)
Joe Perchesd2182b62011-12-15 14:55:53 -0800693 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -0800694 "Updated target sta: %pM, rate caps: 0x%X\n",
695 bss_conf->bssid, be32_to_cpu(trate.capflags));
Sujith2c76ef82010-05-17 12:01:18 +0530696}
697
Luis R. Rodriguez9edd9522010-07-13 21:27:25 -0400698static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv,
699 struct ieee80211_vif *vif,
700 struct ieee80211_sta *sta,
701 enum ieee80211_ampdu_mlme_action action,
702 u16 tid)
Sujithfb9987d2010-03-17 14:25:25 +0530703{
704 struct ath_common *common = ath9k_hw_common(priv->ah);
705 struct ath9k_htc_target_aggr aggr;
Dan Carpenter277a64d2010-05-08 18:23:20 +0200706 struct ath9k_htc_sta *ista;
Sujithfb9987d2010-03-17 14:25:25 +0530707 int ret = 0;
708 u8 cmd_rsp;
709
Dan Carpenter0730d112010-05-08 18:24:02 +0200710 if (tid >= ATH9K_HTC_MAX_TID)
Sujithfb9987d2010-03-17 14:25:25 +0530711 return -EINVAL;
712
Sujithfb9987d2010-03-17 14:25:25 +0530713 memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
Sujithef98c3c2010-03-29 16:07:11 +0530714 ista = (struct ath9k_htc_sta *) sta->drv_priv;
Sujithfb9987d2010-03-17 14:25:25 +0530715
Sujithef98c3c2010-03-29 16:07:11 +0530716 aggr.sta_index = ista->index;
Sujithd7ca2132010-06-15 10:24:37 +0530717 aggr.tidno = tid & 0xf;
718 aggr.aggr_enable = (action == IEEE80211_AMPDU_TX_START) ? true : false;
Sujithef98c3c2010-03-29 16:07:11 +0530719
Sujithfb9987d2010-03-17 14:25:25 +0530720 WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
721 if (ret)
Joe Perchesd2182b62011-12-15 14:55:53 -0800722 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -0800723 "Unable to %s TX aggregation for (%pM, %d)\n",
724 (aggr.aggr_enable) ? "start" : "stop", sta->addr, tid);
Sujithfb9987d2010-03-17 14:25:25 +0530725 else
Joe Perchesd2182b62011-12-15 14:55:53 -0800726 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -0800727 "%s TX aggregation for (%pM, %d)\n",
728 (aggr.aggr_enable) ? "Starting" : "Stopping",
729 sta->addr, tid);
Sujithd7ca2132010-06-15 10:24:37 +0530730
Sujith Manoharan658ef042011-04-13 11:25:00 +0530731 spin_lock_bh(&priv->tx.tx_lock);
Sujithd7ca2132010-06-15 10:24:37 +0530732 ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
Sujith Manoharan658ef042011-04-13 11:25:00 +0530733 spin_unlock_bh(&priv->tx.tx_lock);
Sujithfb9987d2010-03-17 14:25:25 +0530734
735 return ret;
736}
737
Sujithfb9987d2010-03-17 14:25:25 +0530738/*******/
739/* ANI */
740/*******/
741
Sujith Manoharana2362542011-02-21 07:49:38 +0530742void ath9k_htc_start_ani(struct ath9k_htc_priv *priv)
Sujithfb9987d2010-03-17 14:25:25 +0530743{
744 struct ath_common *common = ath9k_hw_common(priv->ah);
745 unsigned long timestamp = jiffies_to_msecs(jiffies);
746
747 common->ani.longcal_timer = timestamp;
748 common->ani.shortcal_timer = timestamp;
749 common->ani.checkani_timer = timestamp;
750
Sujith Manoharand8a2c512012-06-25 13:54:41 +0530751 set_bit(OP_ANI_RUNNING, &priv->op_flags);
Sujith Manoharana2362542011-02-21 07:49:38 +0530752
753 ieee80211_queue_delayed_work(common->hw, &priv->ani_work,
Sujithfb9987d2010-03-17 14:25:25 +0530754 msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
755}
756
Sujith Manoharana2362542011-02-21 07:49:38 +0530757void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv)
758{
759 cancel_delayed_work_sync(&priv->ani_work);
Sujith Manoharand8a2c512012-06-25 13:54:41 +0530760 clear_bit(OP_ANI_RUNNING, &priv->op_flags);
Sujith Manoharana2362542011-02-21 07:49:38 +0530761}
762
763void ath9k_htc_ani_work(struct work_struct *work)
Sujithfb9987d2010-03-17 14:25:25 +0530764{
765 struct ath9k_htc_priv *priv =
Sujith Manoharana2362542011-02-21 07:49:38 +0530766 container_of(work, struct ath9k_htc_priv, ani_work.work);
Sujithfb9987d2010-03-17 14:25:25 +0530767 struct ath_hw *ah = priv->ah;
768 struct ath_common *common = ath9k_hw_common(ah);
769 bool longcal = false;
770 bool shortcal = false;
771 bool aniflag = false;
772 unsigned int timestamp = jiffies_to_msecs(jiffies);
773 u32 cal_interval, short_cal_interval;
774
Sujith Manoharana2362542011-02-21 07:49:38 +0530775 short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
776 ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
Sujithfb9987d2010-03-17 14:25:25 +0530777
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530778 /* Only calibrate if awake */
779 if (ah->power_mode != ATH9K_PM_AWAKE)
780 goto set_timer;
781
Sujithfb9987d2010-03-17 14:25:25 +0530782 /* Long calibration runs independently of short calibration. */
783 if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
784 longcal = true;
Joe Perchesd2182b62011-12-15 14:55:53 -0800785 ath_dbg(common, ANI, "longcal @%lu\n", jiffies);
Sujithfb9987d2010-03-17 14:25:25 +0530786 common->ani.longcal_timer = timestamp;
787 }
788
789 /* Short calibration applies only while caldone is false */
790 if (!common->ani.caldone) {
791 if ((timestamp - common->ani.shortcal_timer) >=
792 short_cal_interval) {
793 shortcal = true;
Joe Perchesd2182b62011-12-15 14:55:53 -0800794 ath_dbg(common, ANI, "shortcal @%lu\n", jiffies);
Sujithfb9987d2010-03-17 14:25:25 +0530795 common->ani.shortcal_timer = timestamp;
796 common->ani.resetcal_timer = timestamp;
797 }
798 } else {
799 if ((timestamp - common->ani.resetcal_timer) >=
800 ATH_RESTART_CALINTERVAL) {
801 common->ani.caldone = ath9k_hw_reset_calvalid(ah);
802 if (common->ani.caldone)
803 common->ani.resetcal_timer = timestamp;
804 }
805 }
806
807 /* Verify whether we must check ANI */
Sujith Manoharane3233002013-06-03 09:19:26 +0530808 if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
Sujithfb9987d2010-03-17 14:25:25 +0530809 aniflag = true;
810 common->ani.checkani_timer = timestamp;
811 }
812
813 /* Skip all processing if there's nothing to do. */
814 if (longcal || shortcal || aniflag) {
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530815
816 ath9k_htc_ps_wakeup(priv);
817
Sujithfb9987d2010-03-17 14:25:25 +0530818 /* Call ANI routine if necessary */
819 if (aniflag)
820 ath9k_hw_ani_monitor(ah, ah->curchan);
821
822 /* Perform calibration if necessary */
Felix Fietkau35ecfe02010-09-29 17:15:26 +0200823 if (longcal || shortcal)
Sujithfb9987d2010-03-17 14:25:25 +0530824 common->ani.caldone =
825 ath9k_hw_calibrate(ah, ah->curchan,
Felix Fietkau82b2d332011-09-03 01:40:23 +0200826 ah->rxchainmask, longcal);
Sujithfb9987d2010-03-17 14:25:25 +0530827
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530828 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530829 }
830
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530831set_timer:
Sujithfb9987d2010-03-17 14:25:25 +0530832 /*
833 * Set timer interval based on previous results.
834 * The interval must be the shortest necessary to satisfy ANI,
835 * short calibration and long calibration.
836 */
837 cal_interval = ATH_LONG_CALINTERVAL;
Sujith Manoharane3233002013-06-03 09:19:26 +0530838 cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
Sujithfb9987d2010-03-17 14:25:25 +0530839 if (!common->ani.caldone)
840 cal_interval = min(cal_interval, (u32)short_cal_interval);
841
Sujith Manoharana2362542011-02-21 07:49:38 +0530842 ieee80211_queue_delayed_work(common->hw, &priv->ani_work,
Sujithfb9987d2010-03-17 14:25:25 +0530843 msecs_to_jiffies(cal_interval));
844}
845
Sujithfb9987d2010-03-17 14:25:25 +0530846/**********************/
847/* mac80211 Callbacks */
848/**********************/
849
Thomas Huehn36323f82012-07-23 21:33:42 +0200850static void ath9k_htc_tx(struct ieee80211_hw *hw,
851 struct ieee80211_tx_control *control,
852 struct sk_buff *skb)
Sujithfb9987d2010-03-17 14:25:25 +0530853{
854 struct ieee80211_hdr *hdr;
855 struct ath9k_htc_priv *priv = hw->priv;
Sujith Manoharan8e86a542011-04-13 11:25:29 +0530856 struct ath_common *common = ath9k_hw_common(priv->ah);
Sujith Manoharan2c5d57f2011-04-13 11:25:47 +0530857 int padpos, padsize, ret, slot;
Sujithfb9987d2010-03-17 14:25:25 +0530858
859 hdr = (struct ieee80211_hdr *) skb->data;
860
861 /* Add the padding after the header if this is not already done */
Felix Fietkauc60c9922013-04-08 00:04:09 +0200862 padpos = ieee80211_hdrlen(hdr->frame_control);
Sujithfb9987d2010-03-17 14:25:25 +0530863 padsize = padpos & 3;
864 if (padsize && skb->len > padpos) {
Sujith Manoharan8e86a542011-04-13 11:25:29 +0530865 if (skb_headroom(skb) < padsize) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800866 ath_dbg(common, XMIT, "No room for padding\n");
Johannes Berg7bb45682011-02-24 14:42:06 +0100867 goto fail_tx;
Sujith Manoharan8e86a542011-04-13 11:25:29 +0530868 }
Sujithfb9987d2010-03-17 14:25:25 +0530869 skb_push(skb, padsize);
870 memmove(skb->data, skb->data + padsize, padpos);
871 }
872
Sujith Manoharan2c5d57f2011-04-13 11:25:47 +0530873 slot = ath9k_htc_tx_get_slot(priv);
874 if (slot < 0) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800875 ath_dbg(common, XMIT, "No free TX slot\n");
Sujith Manoharan2c5d57f2011-04-13 11:25:47 +0530876 goto fail_tx;
877 }
878
Thomas Huehn36323f82012-07-23 21:33:42 +0200879 ret = ath9k_htc_tx_start(priv, control->sta, skb, slot, false);
Sujith7757dfe2010-03-29 16:07:17 +0530880 if (ret != 0) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800881 ath_dbg(common, XMIT, "Tx failed\n");
Sujith Manoharan2c5d57f2011-04-13 11:25:47 +0530882 goto clear_slot;
Sujithfb9987d2010-03-17 14:25:25 +0530883 }
884
Sujith Manoharan8e86a542011-04-13 11:25:29 +0530885 ath9k_htc_check_stop_queues(priv);
886
Johannes Berg7bb45682011-02-24 14:42:06 +0100887 return;
Sujithfb9987d2010-03-17 14:25:25 +0530888
Sujith Manoharan2c5d57f2011-04-13 11:25:47 +0530889clear_slot:
890 ath9k_htc_tx_clear_slot(priv, slot);
Sujithfb9987d2010-03-17 14:25:25 +0530891fail_tx:
892 dev_kfree_skb_any(skb);
Sujithfb9987d2010-03-17 14:25:25 +0530893}
894
Sujith881ac6a2010-06-01 15:14:11 +0530895static int ath9k_htc_start(struct ieee80211_hw *hw)
Sujithfb9987d2010-03-17 14:25:25 +0530896{
897 struct ath9k_htc_priv *priv = hw->priv;
898 struct ath_hw *ah = priv->ah;
899 struct ath_common *common = ath9k_hw_common(ah);
Karl Beldan675a0b02013-03-25 16:26:57 +0100900 struct ieee80211_channel *curchan = hw->conf.chandef.chan;
Sujithfb9987d2010-03-17 14:25:25 +0530901 struct ath9k_channel *init_channel;
902 int ret = 0;
903 enum htc_phymode mode;
Sujith7f1f5a02010-04-16 11:54:03 +0530904 __be16 htc_mode;
Sujithfb9987d2010-03-17 14:25:25 +0530905 u8 cmd_rsp;
906
Sujith881ac6a2010-06-01 15:14:11 +0530907 mutex_lock(&priv->mutex);
908
Joe Perchesd2182b62011-12-15 14:55:53 -0800909 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -0800910 "Starting driver with initial channel: %d MHz\n",
911 curchan->center_freq);
Sujithfb9987d2010-03-17 14:25:25 +0530912
Sujith21d51302010-06-01 15:14:18 +0530913 /* Ensure that HW is awake before flushing RX */
914 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
915 WMI_CMD(WMI_FLUSH_RECV_CMDID);
916
Sujithfb9987d2010-03-17 14:25:25 +0530917 /* setup initial channel */
Felix Fietkau2297f1c2013-10-11 23:30:57 +0200918 init_channel = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef);
Sujithfb9987d2010-03-17 14:25:25 +0530919
Felix Fietkau20bd2a02010-07-31 00:12:00 +0200920 ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
Sujithfb9987d2010-03-17 14:25:25 +0530921 if (ret) {
Joe Perches38002762010-12-02 19:12:36 -0800922 ath_err(common,
923 "Unable to reset hardware; reset status %d (freq %u MHz)\n",
924 ret, curchan->center_freq);
Sujith881ac6a2010-06-01 15:14:11 +0530925 mutex_unlock(&priv->mutex);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +0530926 return ret;
Sujithfb9987d2010-03-17 14:25:25 +0530927 }
928
Rajkumar Manoharanb2a5c3d2011-01-31 23:47:45 +0530929 ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit,
930 &priv->curtxpow);
Sujithfb9987d2010-03-17 14:25:25 +0530931
932 mode = ath9k_htc_get_curmode(priv, init_channel);
933 htc_mode = cpu_to_be16(mode);
934 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
Sujithfb9987d2010-03-17 14:25:25 +0530935 WMI_CMD(WMI_ATH_INIT_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +0530936 WMI_CMD(WMI_START_RECV_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +0530937
938 ath9k_host_rx_init(priv);
939
Sujith Manoharan3a0593e2011-04-20 14:33:28 +0530940 ret = ath9k_htc_update_cap_target(priv, 0);
Sujith Manoharan1057b752011-02-21 07:48:09 +0530941 if (ret)
Joe Perchesd2182b62011-12-15 14:55:53 -0800942 ath_dbg(common, CONFIG,
Sujith Manoharan1057b752011-02-21 07:48:09 +0530943 "Failed to update capability in target\n");
944
Sujith Manoharand8a2c512012-06-25 13:54:41 +0530945 clear_bit(OP_INVALID, &priv->op_flags);
Sujithfb9987d2010-03-17 14:25:25 +0530946 htc_start(priv->htc);
947
Sujith Manoharan658ef042011-04-13 11:25:00 +0530948 spin_lock_bh(&priv->tx.tx_lock);
Sujith Manoharan8e86a542011-04-13 11:25:29 +0530949 priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
Sujith Manoharan658ef042011-04-13 11:25:00 +0530950 spin_unlock_bh(&priv->tx.tx_lock);
Sujith7757dfe2010-03-29 16:07:17 +0530951
952 ieee80211_wake_queues(hw);
953
Sujith Manoharan859c3ca2011-04-13 11:26:39 +0530954 mod_timer(&priv->tx.cleanup_timer,
955 jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
956
Sujith Manoharanbf047fc2012-02-22 12:41:36 +0530957 ath9k_htc_start_btcoex(priv);
958
Vivek Natarajan8a8572a2010-04-27 13:05:37 +0530959 mutex_unlock(&priv->mutex);
960
961 return ret;
962}
963
Sujith881ac6a2010-06-01 15:14:11 +0530964static void ath9k_htc_stop(struct ieee80211_hw *hw)
Sujithfb9987d2010-03-17 14:25:25 +0530965{
966 struct ath9k_htc_priv *priv = hw->priv;
967 struct ath_hw *ah = priv->ah;
968 struct ath_common *common = ath9k_hw_common(ah);
Sujith Manoharan0ff2b5c2011-04-20 11:00:34 +0530969 int ret __attribute__ ((unused));
Sujithfb9987d2010-03-17 14:25:25 +0530970 u8 cmd_rsp;
971
Sujith881ac6a2010-06-01 15:14:11 +0530972 mutex_lock(&priv->mutex);
973
Sujith Manoharand8a2c512012-06-25 13:54:41 +0530974 if (test_bit(OP_INVALID, &priv->op_flags)) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800975 ath_dbg(common, ANY, "Device not present\n");
Sujith881ac6a2010-06-01 15:14:11 +0530976 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +0530977 return;
978 }
979
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530980 ath9k_htc_ps_wakeup(priv);
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530981
Sujithfb9987d2010-03-17 14:25:25 +0530982 WMI_CMD(WMI_DISABLE_INTR_CMDID);
983 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
984 WMI_CMD(WMI_STOP_RECV_CMDID);
Stanislaw Gruszkaea888352011-01-25 14:15:12 +0100985
Stanislaw Gruszkaea888352011-01-25 14:15:12 +0100986 tasklet_kill(&priv->rx_tasklet);
Stanislaw Gruszkaea888352011-01-25 14:15:12 +0100987
Sujith Manoharan859c3ca2011-04-13 11:26:39 +0530988 del_timer_sync(&priv->tx.cleanup_timer);
Sujith Manoharanb587fc82011-04-13 11:25:59 +0530989 ath9k_htc_tx_drain(priv);
Sujith Manoharanf4c88992011-04-13 11:23:52 +0530990 ath9k_wmi_event_drain(priv);
991
Stanislaw Gruszkaea888352011-01-25 14:15:12 +0100992 mutex_unlock(&priv->mutex);
993
994 /* Cancel all the running timers/work .. */
995 cancel_work_sync(&priv->fatal_work);
996 cancel_work_sync(&priv->ps_work);
Sujith Manoharand244f212011-04-28 16:14:05 +0530997
998#ifdef CONFIG_MAC80211_LEDS
999 cancel_work_sync(&priv->led_work);
1000#endif
Sujith Manoharana2362542011-02-21 07:49:38 +05301001 ath9k_htc_stop_ani(priv);
Stanislaw Gruszkaea888352011-01-25 14:15:12 +01001002
1003 mutex_lock(&priv->mutex);
1004
Sujith Manoharanbf047fc2012-02-22 12:41:36 +05301005 ath9k_htc_stop_btcoex(priv);
Vivek Natarajan21cb9872010-08-18 19:57:49 +05301006
Sujith Manoharana97b4782011-02-21 07:48:00 +05301007 /* Remove a monitor interface if it's present. */
1008 if (priv->ah->is_monitoring)
1009 ath9k_htc_remove_monitor_interface(priv);
1010
Sujithe9201f02010-06-01 15:14:17 +05301011 ath9k_hw_phy_disable(ah);
1012 ath9k_hw_disable(ah);
Sujithe9201f02010-06-01 15:14:17 +05301013 ath9k_htc_ps_restore(priv);
1014 ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
1015
Sujith Manoharand8a2c512012-06-25 13:54:41 +05301016 set_bit(OP_INVALID, &priv->op_flags);
Sujithfb9987d2010-03-17 14:25:25 +05301017
Joe Perchesd2182b62011-12-15 14:55:53 -08001018 ath_dbg(common, CONFIG, "Driver halt\n");
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301019 mutex_unlock(&priv->mutex);
1020}
1021
Sujithfb9987d2010-03-17 14:25:25 +05301022static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
1023 struct ieee80211_vif *vif)
1024{
1025 struct ath9k_htc_priv *priv = hw->priv;
1026 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1027 struct ath_common *common = ath9k_hw_common(priv->ah);
1028 struct ath9k_htc_target_vif hvif;
1029 int ret = 0;
1030 u8 cmd_rsp;
1031
1032 mutex_lock(&priv->mutex);
1033
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301034 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301035 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1036 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1037
1038 switch (vif->type) {
1039 case NL80211_IFTYPE_STATION:
Sujith Manoharane4c62502011-04-13 11:24:43 +05301040 hvif.opmode = HTC_M_STA;
Sujithfb9987d2010-03-17 14:25:25 +05301041 break;
1042 case NL80211_IFTYPE_ADHOC:
Sujith Manoharane4c62502011-04-13 11:24:43 +05301043 hvif.opmode = HTC_M_IBSS;
Sujithfb9987d2010-03-17 14:25:25 +05301044 break;
Sujith Manoharanda8d9d92011-02-21 07:49:23 +05301045 case NL80211_IFTYPE_AP:
Sujith Manoharane4c62502011-04-13 11:24:43 +05301046 hvif.opmode = HTC_M_HOSTAP;
Sujith Manoharanda8d9d92011-02-21 07:49:23 +05301047 break;
Javier Cardona594e65b2013-05-08 10:16:46 -07001048 case NL80211_IFTYPE_MESH_POINT:
1049 hvif.opmode = HTC_M_WDS; /* close enough */
1050 break;
Sujithfb9987d2010-03-17 14:25:25 +05301051 default:
Joe Perches38002762010-12-02 19:12:36 -08001052 ath_err(common,
Sujithfb9987d2010-03-17 14:25:25 +05301053 "Interface type %d not yet supported\n", vif->type);
1054 ret = -EOPNOTSUPP;
1055 goto out;
1056 }
1057
Sujithfb9987d2010-03-17 14:25:25 +05301058 /* Index starts from zero on the target */
Sujith Manoharana97b4782011-02-21 07:48:00 +05301059 avp->index = hvif.index = ffz(priv->vif_slot);
Sujithfb9987d2010-03-17 14:25:25 +05301060 hvif.rtsthreshold = cpu_to_be16(2304);
1061 WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
1062 if (ret)
1063 goto out;
1064
Sujithfb9987d2010-03-17 14:25:25 +05301065 /*
1066 * We need a node in target to tx mgmt frames
1067 * before association.
1068 */
1069 ret = ath9k_htc_add_station(priv, vif, NULL);
Sujith Manoharanab77c702011-02-21 07:48:16 +05301070 if (ret) {
1071 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
Sujithfb9987d2010-03-17 14:25:25 +05301072 goto out;
Sujith Manoharanab77c702011-02-21 07:48:16 +05301073 }
Sujithfb9987d2010-03-17 14:25:25 +05301074
Mathy Vanhoef657eb172013-11-28 12:21:45 +01001075 ath9k_htc_set_mac_bssid_mask(priv, vif);
Sujith Manoharan585895c2011-02-21 07:48:46 +05301076
Sujith Manoharana97b4782011-02-21 07:48:00 +05301077 priv->vif_slot |= (1 << avp->index);
Sujith Manoharanab77c702011-02-21 07:48:16 +05301078 priv->nvifs++;
Sujith Manoharana97b4782011-02-21 07:48:00 +05301079
Sujith Manoharan0df83592011-02-21 07:49:15 +05301080 INC_VIF(priv, vif->type);
Sujith Manoharan832f6a12011-04-13 11:23:08 +05301081
1082 if ((vif->type == NL80211_IFTYPE_AP) ||
Javier Cardona594e65b2013-05-08 10:16:46 -07001083 (vif->type == NL80211_IFTYPE_MESH_POINT) ||
Sujith Manoharan832f6a12011-04-13 11:23:08 +05301084 (vif->type == NL80211_IFTYPE_ADHOC))
1085 ath9k_htc_assign_bslot(priv, vif);
1086
Sujith Manoharanffbe7c82011-02-21 07:49:31 +05301087 ath9k_htc_set_opmode(priv);
Sujith Manoharan0df83592011-02-21 07:49:15 +05301088
Sujith Manoharana2362542011-02-21 07:49:38 +05301089 if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
Sujith Manoharand8a2c512012-06-25 13:54:41 +05301090 !test_bit(OP_ANI_RUNNING, &priv->op_flags)) {
Sujith Manoharan60ca9f82012-07-17 17:15:37 +05301091 ath9k_hw_set_tsfadjust(priv->ah, true);
Sujith Manoharana2362542011-02-21 07:49:38 +05301092 ath9k_htc_start_ani(priv);
Sujith Manoharan9b674a02011-04-13 11:23:17 +05301093 }
Sujith Manoharana2362542011-02-21 07:49:38 +05301094
Joe Perchesd2182b62011-12-15 14:55:53 -08001095 ath_dbg(common, CONFIG, "Attach a VIF of type: %d at idx: %d\n",
1096 vif->type, avp->index);
Sujith Manoharana97b4782011-02-21 07:48:00 +05301097
Sujithfb9987d2010-03-17 14:25:25 +05301098out:
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301099 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301100 mutex_unlock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301101
Sujithfb9987d2010-03-17 14:25:25 +05301102 return ret;
1103}
1104
1105static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
1106 struct ieee80211_vif *vif)
1107{
1108 struct ath9k_htc_priv *priv = hw->priv;
1109 struct ath_common *common = ath9k_hw_common(priv->ah);
1110 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1111 struct ath9k_htc_target_vif hvif;
1112 int ret = 0;
1113 u8 cmd_rsp;
1114
Sujithfb9987d2010-03-17 14:25:25 +05301115 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301116 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301117
1118 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1119 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1120 hvif.index = avp->index;
1121 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
Sujith Manoharan0ff2b5c2011-04-20 11:00:34 +05301122 if (ret) {
1123 ath_err(common, "Unable to remove interface at idx: %d\n",
1124 avp->index);
1125 }
Sujithfb9987d2010-03-17 14:25:25 +05301126 priv->nvifs--;
Sujith Manoharana97b4782011-02-21 07:48:00 +05301127 priv->vif_slot &= ~(1 << avp->index);
Sujithfb9987d2010-03-17 14:25:25 +05301128
1129 ath9k_htc_remove_station(priv, vif, NULL);
Sujithfb9987d2010-03-17 14:25:25 +05301130
Sujith Manoharan0df83592011-02-21 07:49:15 +05301131 DEC_VIF(priv, vif->type);
Sujith Manoharan832f6a12011-04-13 11:23:08 +05301132
1133 if ((vif->type == NL80211_IFTYPE_AP) ||
Javier Cardona594e65b2013-05-08 10:16:46 -07001134 vif->type == NL80211_IFTYPE_MESH_POINT ||
Sujith Manoharan832f6a12011-04-13 11:23:08 +05301135 (vif->type == NL80211_IFTYPE_ADHOC))
1136 ath9k_htc_remove_bslot(priv, vif);
1137
Sujith Manoharanffbe7c82011-02-21 07:49:31 +05301138 ath9k_htc_set_opmode(priv);
Sujith Manoharan0df83592011-02-21 07:49:15 +05301139
Mathy Vanhoef657eb172013-11-28 12:21:45 +01001140 ath9k_htc_set_mac_bssid_mask(priv, vif);
Sujith Manoharandb321242011-05-17 12:41:41 +05301141
Sujith Manoharana2362542011-02-21 07:49:38 +05301142 /*
1143 * Stop ANI only if there are no associated station interfaces.
1144 */
1145 if ((vif->type == NL80211_IFTYPE_AP) && (priv->num_ap_vif == 0)) {
1146 priv->rearm_ani = false;
Johannes Berg8b2c9822012-11-06 20:23:30 +01001147 ieee80211_iterate_active_interfaces_atomic(
1148 priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
1149 ath9k_htc_vif_iter, priv);
Sujith Manoharana2362542011-02-21 07:49:38 +05301150 if (!priv->rearm_ani)
1151 ath9k_htc_stop_ani(priv);
1152 }
1153
Joe Perchesd2182b62011-12-15 14:55:53 -08001154 ath_dbg(common, CONFIG, "Detach Interface at idx: %d\n", avp->index);
Sujith Manoharana97b4782011-02-21 07:48:00 +05301155
Sujithcb551df2010-06-01 15:14:12 +05301156 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301157 mutex_unlock(&priv->mutex);
1158}
1159
1160static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
1161{
1162 struct ath9k_htc_priv *priv = hw->priv;
1163 struct ath_common *common = ath9k_hw_common(priv->ah);
1164 struct ieee80211_conf *conf = &hw->conf;
Sujith Manoharan6bcfe672012-06-25 13:54:49 +05301165 bool chip_reset = false;
1166 int ret = 0;
Sujithfb9987d2010-03-17 14:25:25 +05301167
1168 mutex_lock(&priv->mutex);
Sujith Manoharan6bcfe672012-06-25 13:54:49 +05301169 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301170
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301171 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Sujith23367762010-06-01 15:14:16 +05301172 mutex_lock(&priv->htc_pm_lock);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301173
Sujith Manoharan6bcfe672012-06-25 13:54:49 +05301174 priv->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
Sujith Manoharan075163b2013-06-20 13:57:07 +05301175 if (!priv->ps_idle)
Sujith Manoharan6bcfe672012-06-25 13:54:49 +05301176 chip_reset = true;
1177
1178 mutex_unlock(&priv->htc_pm_lock);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301179 }
1180
Sujith Manoharan55de80d2011-01-05 01:06:21 +05301181 /*
1182 * Monitor interface should be added before
1183 * IEEE80211_CONF_CHANGE_CHANNEL is handled.
1184 */
1185 if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
Sujith Manoharana97b4782011-02-21 07:48:00 +05301186 if ((conf->flags & IEEE80211_CONF_MONITOR) &&
1187 !priv->ah->is_monitoring)
1188 ath9k_htc_add_monitor_interface(priv);
1189 else if (priv->ah->is_monitoring)
1190 ath9k_htc_remove_monitor_interface(priv);
Sujith Manoharan55de80d2011-01-05 01:06:21 +05301191 }
1192
Sujith Manoharan6bcfe672012-06-25 13:54:49 +05301193 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || chip_reset) {
Karl Beldan675a0b02013-03-25 16:26:57 +01001194 struct ieee80211_channel *curchan = hw->conf.chandef.chan;
Sujithfb9987d2010-03-17 14:25:25 +05301195 int pos = curchan->hw_value;
Sujithfb9987d2010-03-17 14:25:25 +05301196
Joe Perchesd2182b62011-12-15 14:55:53 -08001197 ath_dbg(common, CONFIG, "Set channel: %d MHz\n",
Joe Perches226afe62010-12-02 19:12:37 -08001198 curchan->center_freq);
Sujithfb9987d2010-03-17 14:25:25 +05301199
Felix Fietkau2297f1c2013-10-11 23:30:57 +02001200 ath9k_cmn_get_channel(hw, priv->ah, &hw->conf.chandef);
Sujithfb9987d2010-03-17 14:25:25 +05301201 if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
Joe Perches38002762010-12-02 19:12:36 -08001202 ath_err(common, "Unable to set channel\n");
Sujith Manoharan6bcfe672012-06-25 13:54:49 +05301203 ret = -EINVAL;
1204 goto out;
Sujithfb9987d2010-03-17 14:25:25 +05301205 }
1206
1207 }
Sujith Manoharan692d6b12010-12-07 16:31:54 +05301208
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301209 if (changed & IEEE80211_CONF_CHANGE_PS) {
1210 if (conf->flags & IEEE80211_CONF_PS) {
1211 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
1212 priv->ps_enabled = true;
1213 } else {
1214 priv->ps_enabled = false;
1215 cancel_work_sync(&priv->ps_work);
1216 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1217 }
1218 }
Sujithfb9987d2010-03-17 14:25:25 +05301219
Sujith Manoharan692d6b12010-12-07 16:31:54 +05301220 if (changed & IEEE80211_CONF_CHANGE_POWER) {
1221 priv->txpowlimit = 2 * conf->power_level;
Rajkumar Manoharanb2a5c3d2011-01-31 23:47:45 +05301222 ath9k_cmn_update_txpow(priv->ah, priv->curtxpow,
1223 priv->txpowlimit, &priv->curtxpow);
Sujith Manoharan692d6b12010-12-07 16:31:54 +05301224 }
1225
Sujith23367762010-06-01 15:14:16 +05301226out:
Sujith Manoharan6bcfe672012-06-25 13:54:49 +05301227 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301228 mutex_unlock(&priv->mutex);
Sujith Manoharan6bcfe672012-06-25 13:54:49 +05301229 return ret;
Sujithfb9987d2010-03-17 14:25:25 +05301230}
1231
1232#define SUPPORTED_FILTERS \
1233 (FIF_PROMISC_IN_BSS | \
1234 FIF_ALLMULTI | \
1235 FIF_CONTROL | \
1236 FIF_PSPOLL | \
1237 FIF_OTHER_BSS | \
1238 FIF_BCN_PRBRESP_PROMISC | \
Rajkumar Manoharan94a40c02010-10-14 10:50:26 +05301239 FIF_PROBE_REQ | \
Sujithfb9987d2010-03-17 14:25:25 +05301240 FIF_FCSFAIL)
1241
1242static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
1243 unsigned int changed_flags,
1244 unsigned int *total_flags,
1245 u64 multicast)
1246{
1247 struct ath9k_htc_priv *priv = hw->priv;
1248 u32 rfilt;
1249
1250 mutex_lock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301251 changed_flags &= SUPPORTED_FILTERS;
1252 *total_flags &= SUPPORTED_FILTERS;
1253
Sujith Manoharand8a2c512012-06-25 13:54:41 +05301254 if (test_bit(OP_INVALID, &priv->op_flags)) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001255 ath_dbg(ath9k_hw_common(priv->ah), ANY,
Rajkumar Manoharan565dfef2011-07-07 23:33:38 +05301256 "Unable to configure filter on invalid state\n");
Larry Finger1ba45b92011-08-27 13:56:00 -05001257 mutex_unlock(&priv->mutex);
Rajkumar Manoharan565dfef2011-07-07 23:33:38 +05301258 return;
1259 }
1260 ath9k_htc_ps_wakeup(priv);
1261
Sujithfb9987d2010-03-17 14:25:25 +05301262 priv->rxfilter = *total_flags;
Sujith0995d112010-03-29 16:07:09 +05301263 rfilt = ath9k_htc_calcrxfilter(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301264 ath9k_hw_setrxfilter(priv->ah, rfilt);
1265
Joe Perchesd2182b62011-12-15 14:55:53 -08001266 ath_dbg(ath9k_hw_common(priv->ah), CONFIG, "Set HW RX filter: 0x%x\n",
1267 rfilt);
Sujithfb9987d2010-03-17 14:25:25 +05301268
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301269 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301270 mutex_unlock(&priv->mutex);
1271}
1272
Stanislaw Gruszkaa243de42014-02-03 11:45:51 +01001273static void ath9k_htc_sta_rc_update_work(struct work_struct *work)
Sujithfb9987d2010-03-17 14:25:25 +05301274{
Stanislaw Gruszkaa243de42014-02-03 11:45:51 +01001275 struct ath9k_htc_sta *ista =
1276 container_of(work, struct ath9k_htc_sta, rc_update_work);
1277 struct ieee80211_sta *sta =
1278 container_of((void *)ista, struct ieee80211_sta, drv_priv);
1279 struct ath9k_htc_priv *priv = ista->htc_priv;
Antonio Quartulli69578022012-08-12 19:36:41 +02001280 struct ath_common *common = ath9k_hw_common(priv->ah);
1281 struct ath9k_htc_target_rate trate;
1282
1283 mutex_lock(&priv->mutex);
1284 ath9k_htc_ps_wakeup(priv);
1285
Stanislaw Gruszka2fa4cb92014-01-28 09:14:48 +01001286 memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
1287 ath9k_htc_setup_rate(priv, sta, &trate);
1288 if (!ath9k_htc_send_rate_cmd(priv, &trate))
1289 ath_dbg(common, CONFIG,
1290 "Supported rates for sta: %pM updated, rate caps: 0x%X\n",
1291 sta->addr, be32_to_cpu(trate.capflags));
1292 else
1293 ath_dbg(common, CONFIG,
1294 "Unable to update supported rates for sta: %pM\n",
1295 sta->addr);
Antonio Quartulli69578022012-08-12 19:36:41 +02001296
1297 ath9k_htc_ps_restore(priv);
1298 mutex_unlock(&priv->mutex);
1299}
1300
Stanislaw Gruszkaa243de42014-02-03 11:45:51 +01001301static int ath9k_htc_sta_add(struct ieee80211_hw *hw,
1302 struct ieee80211_vif *vif,
1303 struct ieee80211_sta *sta)
1304{
1305 struct ath9k_htc_priv *priv = hw->priv;
1306 struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
1307 int ret;
1308
1309 mutex_lock(&priv->mutex);
1310 ath9k_htc_ps_wakeup(priv);
1311 ret = ath9k_htc_add_station(priv, vif, sta);
1312 if (!ret) {
1313 INIT_WORK(&ista->rc_update_work, ath9k_htc_sta_rc_update_work);
1314 ista->htc_priv = priv;
1315 ath9k_htc_init_rate(priv, sta);
1316 }
1317 ath9k_htc_ps_restore(priv);
1318 mutex_unlock(&priv->mutex);
1319
1320 return ret;
1321}
1322
1323static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
1324 struct ieee80211_vif *vif,
1325 struct ieee80211_sta *sta)
1326{
1327 struct ath9k_htc_priv *priv = hw->priv;
1328 struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
1329 int ret;
1330
1331 cancel_work_sync(&ista->rc_update_work);
1332
1333 mutex_lock(&priv->mutex);
1334 ath9k_htc_ps_wakeup(priv);
1335 htc_sta_drain(priv->htc, ista->index);
1336 ret = ath9k_htc_remove_station(priv, vif, sta);
1337 ath9k_htc_ps_restore(priv);
1338 mutex_unlock(&priv->mutex);
1339
1340 return ret;
1341}
1342
1343static void ath9k_htc_sta_rc_update(struct ieee80211_hw *hw,
1344 struct ieee80211_vif *vif,
1345 struct ieee80211_sta *sta, u32 changed)
1346{
1347 struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
1348
1349 if (!(changed & IEEE80211_RC_SUPP_RATES_CHANGED))
1350 return;
1351
1352 schedule_work(&ista->rc_update_work);
1353}
1354
Eliad Peller8a3a3c82011-10-02 10:15:52 +02001355static int ath9k_htc_conf_tx(struct ieee80211_hw *hw,
1356 struct ieee80211_vif *vif, u16 queue,
Sujithfb9987d2010-03-17 14:25:25 +05301357 const struct ieee80211_tx_queue_params *params)
1358{
1359 struct ath9k_htc_priv *priv = hw->priv;
1360 struct ath_common *common = ath9k_hw_common(priv->ah);
1361 struct ath9k_tx_queue_info qi;
1362 int ret = 0, qnum;
1363
Sujith Manoharanbea843c2012-11-21 18:13:10 +05301364 if (queue >= IEEE80211_NUM_ACS)
Sujithfb9987d2010-03-17 14:25:25 +05301365 return 0;
1366
1367 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301368 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301369
1370 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
1371
1372 qi.tqi_aifs = params->aifs;
1373 qi.tqi_cwmin = params->cw_min;
1374 qi.tqi_cwmax = params->cw_max;
Felix Fietkau531bd072012-07-15 19:53:34 +02001375 qi.tqi_burstTime = params->txop * 32;
Sujithfb9987d2010-03-17 14:25:25 +05301376
1377 qnum = get_hw_qnum(queue, priv->hwq_map);
1378
Joe Perchesd2182b62011-12-15 14:55:53 -08001379 ath_dbg(common, CONFIG,
Joe Perches226afe62010-12-02 19:12:37 -08001380 "Configure tx [queue/hwq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
1381 queue, qnum, params->aifs, params->cw_min,
1382 params->cw_max, params->txop);
Sujithfb9987d2010-03-17 14:25:25 +05301383
Sujithe1572c52010-03-24 13:42:13 +05301384 ret = ath_htc_txq_update(priv, qnum, &qi);
Sujith764580f2010-06-01 15:14:19 +05301385 if (ret) {
Joe Perches38002762010-12-02 19:12:36 -08001386 ath_err(common, "TXQ Update failed\n");
Sujith764580f2010-06-01 15:14:19 +05301387 goto out;
1388 }
Sujithfb9987d2010-03-17 14:25:25 +05301389
Sujith764580f2010-06-01 15:14:19 +05301390 if ((priv->ah->opmode == NL80211_IFTYPE_ADHOC) &&
Sujith Manoharanbea843c2012-11-21 18:13:10 +05301391 (qnum == priv->hwq_map[IEEE80211_AC_BE]))
Sujith764580f2010-06-01 15:14:19 +05301392 ath9k_htc_beaconq_config(priv);
1393out:
Sujithcb551df2010-06-01 15:14:12 +05301394 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301395 mutex_unlock(&priv->mutex);
1396
1397 return ret;
1398}
1399
1400static int ath9k_htc_set_key(struct ieee80211_hw *hw,
1401 enum set_key_cmd cmd,
1402 struct ieee80211_vif *vif,
1403 struct ieee80211_sta *sta,
1404 struct ieee80211_key_conf *key)
1405{
1406 struct ath9k_htc_priv *priv = hw->priv;
1407 struct ath_common *common = ath9k_hw_common(priv->ah);
1408 int ret = 0;
1409
Sujithe1572c52010-03-24 13:42:13 +05301410 if (htc_modparam_nohwcrypt)
Sujithfb9987d2010-03-17 14:25:25 +05301411 return -ENOSPC;
1412
Antonio Quartullid7d312c2012-01-17 23:13:30 +01001413 if ((vif->type == NL80211_IFTYPE_ADHOC ||
1414 vif->type == NL80211_IFTYPE_MESH_POINT) &&
1415 (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
1416 key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
1417 !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
1418 /*
1419 * For now, disable hw crypto for the RSN IBSS group keys. This
1420 * could be optimized in the future to use a modified key cache
1421 * design to support per-STA RX GTK, but until that gets
1422 * implemented, use of software crypto for group addressed
1423 * frames is a acceptable to allow RSN IBSS to be used.
1424 */
1425 return -EOPNOTSUPP;
1426 }
1427
Sujithfb9987d2010-03-17 14:25:25 +05301428 mutex_lock(&priv->mutex);
Joe Perchesd2182b62011-12-15 14:55:53 -08001429 ath_dbg(common, CONFIG, "Set HW Key\n");
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301430 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301431
1432 switch (cmd) {
1433 case SET_KEY:
Bruno Randolf040e5392010-09-08 16:05:04 +09001434 ret = ath_key_config(common, vif, sta, key);
Sujithfb9987d2010-03-17 14:25:25 +05301435 if (ret >= 0) {
1436 key->hw_key_idx = ret;
1437 /* push IV and Michael MIC generation to stack */
1438 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Johannes Berg97359d12010-08-10 09:46:38 +02001439 if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
Sujithfb9987d2010-03-17 14:25:25 +05301440 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
Johannes Berg97359d12010-08-10 09:46:38 +02001441 if (priv->ah->sw_mgmt_crypto &&
1442 key->cipher == WLAN_CIPHER_SUITE_CCMP)
Johannes Berge548c492012-09-04 17:08:23 +02001443 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
Sujithfb9987d2010-03-17 14:25:25 +05301444 ret = 0;
1445 }
1446 break;
1447 case DISABLE_KEY:
Bruno Randolf040e5392010-09-08 16:05:04 +09001448 ath_key_delete(common, key);
Sujithfb9987d2010-03-17 14:25:25 +05301449 break;
1450 default:
1451 ret = -EINVAL;
1452 }
1453
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301454 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301455 mutex_unlock(&priv->mutex);
1456
1457 return ret;
1458}
1459
Sujith Manoharan0cd075d2011-05-17 12:42:03 +05301460static void ath9k_htc_set_bssid(struct ath9k_htc_priv *priv)
1461{
1462 struct ath_common *common = ath9k_hw_common(priv->ah);
1463
1464 ath9k_hw_write_associd(priv->ah);
Joe Perchesd2182b62011-12-15 14:55:53 -08001465 ath_dbg(common, CONFIG, "BSSID: %pM aid: 0x%x\n",
Sujith Manoharan0cd075d2011-05-17 12:42:03 +05301466 common->curbssid, common->curaid);
1467}
1468
1469static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
1470{
1471 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
1472 struct ath_common *common = ath9k_hw_common(priv->ah);
1473 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
1474
1475 if ((vif->type == NL80211_IFTYPE_STATION) && bss_conf->assoc) {
1476 common->curaid = bss_conf->aid;
1477 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1478 }
1479}
1480
1481static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv)
1482{
1483 if (priv->num_sta_assoc_vif == 1) {
Johannes Berg8b2c9822012-11-06 20:23:30 +01001484 ieee80211_iterate_active_interfaces_atomic(
1485 priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
1486 ath9k_htc_bss_iter, priv);
Sujith Manoharan0cd075d2011-05-17 12:42:03 +05301487 ath9k_htc_set_bssid(priv);
1488 }
1489}
1490
Sujithfb9987d2010-03-17 14:25:25 +05301491static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
1492 struct ieee80211_vif *vif,
1493 struct ieee80211_bss_conf *bss_conf,
1494 u32 changed)
1495{
1496 struct ath9k_htc_priv *priv = hw->priv;
1497 struct ath_hw *ah = priv->ah;
1498 struct ath_common *common = ath9k_hw_common(ah);
1499
1500 mutex_lock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301501 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301502
Sujith Manoharane7a2a4f2011-02-27 09:20:40 +05301503 if (changed & BSS_CHANGED_ASSOC) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001504 ath_dbg(common, CONFIG, "BSS Changed ASSOC %d\n",
Sujith Manoharan0cd075d2011-05-17 12:42:03 +05301505 bss_conf->assoc);
Sujith Manoharane7a2a4f2011-02-27 09:20:40 +05301506
Sujith Manoharan0cd075d2011-05-17 12:42:03 +05301507 bss_conf->assoc ?
1508 priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--;
Sujith Manoharane7a2a4f2011-02-27 09:20:40 +05301509
Sujith Manoharan0cd075d2011-05-17 12:42:03 +05301510 if (priv->ah->opmode == NL80211_IFTYPE_STATION) {
Rajkumar Manoharan931cb032012-06-20 16:29:20 +05301511 ath9k_htc_choose_set_bssid(priv);
Sujith Manoharan0cd075d2011-05-17 12:42:03 +05301512 if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1))
Sujith Manoharane7a2a4f2011-02-27 09:20:40 +05301513 ath9k_htc_start_ani(priv);
Sujith Manoharan0cd075d2011-05-17 12:42:03 +05301514 else if (priv->num_sta_assoc_vif == 0)
Sujith Manoharane7a2a4f2011-02-27 09:20:40 +05301515 ath9k_htc_stop_ani(priv);
1516 }
Sujithfb9987d2010-03-17 14:25:25 +05301517 }
1518
Rajkumar Manoharan931cb032012-06-20 16:29:20 +05301519 if (changed & BSS_CHANGED_IBSS) {
Sujith Manoharan0cd075d2011-05-17 12:42:03 +05301520 if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
1521 common->curaid = bss_conf->aid;
Sujith Manoharane7a2a4f2011-02-27 09:20:40 +05301522 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
Sujith Manoharan0cd075d2011-05-17 12:42:03 +05301523 ath9k_htc_set_bssid(priv);
Sujith Manoharane7a2a4f2011-02-27 09:20:40 +05301524 }
Sujithfb9987d2010-03-17 14:25:25 +05301525 }
1526
Sujith Manoharana5fae372011-02-21 07:49:53 +05301527 if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001528 ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n",
1529 bss_conf->bssid);
Sujith Manoharan9b674a02011-04-13 11:23:17 +05301530 ath9k_htc_set_tsfadjust(priv, vif);
Sujith Manoharand8a2c512012-06-25 13:54:41 +05301531 set_bit(OP_ENABLE_BEACON, &priv->op_flags);
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301532 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301533 }
1534
Sujith Manoharana5fae372011-02-21 07:49:53 +05301535 if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) {
1536 /*
1537 * Disable SWBA interrupt only if there are no
Javier Cardona594e65b2013-05-08 10:16:46 -07001538 * concurrent AP/mesh or IBSS interfaces.
Sujith Manoharana5fae372011-02-21 07:49:53 +05301539 */
Javier Cardona594e65b2013-05-08 10:16:46 -07001540 if ((priv->num_ap_vif + priv->num_mbss_vif <= 1) ||
1541 priv->num_ibss_vif) {
Joe Perchesd2182b62011-12-15 14:55:53 -08001542 ath_dbg(common, CONFIG,
Sujith Manoharana5fae372011-02-21 07:49:53 +05301543 "Beacon disabled for BSS: %pM\n",
1544 bss_conf->bssid);
Sujith Manoharand8a2c512012-06-25 13:54:41 +05301545 clear_bit(OP_ENABLE_BEACON, &priv->op_flags);
Sujith Manoharana5fae372011-02-21 07:49:53 +05301546 ath9k_htc_beacon_config(priv, vif);
1547 }
1548 }
1549
1550 if (changed & BSS_CHANGED_BEACON_INT) {
1551 /*
Javier Cardona594e65b2013-05-08 10:16:46 -07001552 * Reset the HW TSF for the first AP or mesh interface.
Sujith Manoharana5fae372011-02-21 07:49:53 +05301553 */
Javier Cardona594e65b2013-05-08 10:16:46 -07001554 if (priv->nvifs == 1 &&
1555 ((priv->ah->opmode == NL80211_IFTYPE_AP &&
1556 vif->type == NL80211_IFTYPE_AP &&
1557 priv->num_ap_vif == 1) ||
1558 (priv->ah->opmode == NL80211_IFTYPE_MESH_POINT &&
1559 vif->type == NL80211_IFTYPE_MESH_POINT &&
1560 priv->num_mbss_vif == 1))) {
Sujith Manoharand8a2c512012-06-25 13:54:41 +05301561 set_bit(OP_TSF_RESET, &priv->op_flags);
Sujith Manoharana5fae372011-02-21 07:49:53 +05301562 }
Joe Perchesd2182b62011-12-15 14:55:53 -08001563 ath_dbg(common, CONFIG,
Sujith Manoharana5fae372011-02-21 07:49:53 +05301564 "Beacon interval changed for BSS: %pM\n",
1565 bss_conf->bssid);
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301566 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301567 }
1568
Sujithfb9987d2010-03-17 14:25:25 +05301569 if (changed & BSS_CHANGED_ERP_SLOT) {
1570 if (bss_conf->use_short_slot)
1571 ah->slottime = 9;
1572 else
1573 ah->slottime = 20;
1574
1575 ath9k_hw_init_global_settings(ah);
1576 }
1577
Sujith2c76ef82010-05-17 12:01:18 +05301578 if (changed & BSS_CHANGED_HT)
1579 ath9k_htc_update_rate(priv, vif, bss_conf);
1580
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301581 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301582 mutex_unlock(&priv->mutex);
1583}
1584
Eliad Peller37a41b42011-09-21 14:06:11 +03001585static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw,
1586 struct ieee80211_vif *vif)
Sujithfb9987d2010-03-17 14:25:25 +05301587{
1588 struct ath9k_htc_priv *priv = hw->priv;
1589 u64 tsf;
1590
1591 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301592 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301593 tsf = ath9k_hw_gettsf64(priv->ah);
Sujithcb551df2010-06-01 15:14:12 +05301594 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301595 mutex_unlock(&priv->mutex);
1596
1597 return tsf;
1598}
1599
Eliad Peller37a41b42011-09-21 14:06:11 +03001600static void ath9k_htc_set_tsf(struct ieee80211_hw *hw,
1601 struct ieee80211_vif *vif, u64 tsf)
Sujithfb9987d2010-03-17 14:25:25 +05301602{
1603 struct ath9k_htc_priv *priv = hw->priv;
1604
1605 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301606 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301607 ath9k_hw_settsf64(priv->ah, tsf);
Sujithcb551df2010-06-01 15:14:12 +05301608 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301609 mutex_unlock(&priv->mutex);
1610}
1611
Eliad Peller37a41b42011-09-21 14:06:11 +03001612static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw,
1613 struct ieee80211_vif *vif)
Sujithfb9987d2010-03-17 14:25:25 +05301614{
1615 struct ath9k_htc_priv *priv = hw->priv;
1616
1617 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301618 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301619 ath9k_hw_reset_tsf(priv->ah);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301620 ath9k_htc_ps_restore(priv);
Sujithcb551df2010-06-01 15:14:12 +05301621 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301622}
1623
1624static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
1625 struct ieee80211_vif *vif,
1626 enum ieee80211_ampdu_mlme_action action,
1627 struct ieee80211_sta *sta,
Johannes Berg0b01f032011-01-18 13:51:05 +01001628 u16 tid, u16 *ssn, u8 buf_size)
Sujithfb9987d2010-03-17 14:25:25 +05301629{
1630 struct ath9k_htc_priv *priv = hw->priv;
Sujithfb9987d2010-03-17 14:25:25 +05301631 struct ath9k_htc_sta *ista;
Sujithd7ca2132010-06-15 10:24:37 +05301632 int ret = 0;
Sujithfb9987d2010-03-17 14:25:25 +05301633
Sujith Manoharan87df8952011-02-21 07:49:08 +05301634 mutex_lock(&priv->mutex);
Sujith Manoharanc58ca5b2011-04-20 11:01:10 +05301635 ath9k_htc_ps_wakeup(priv);
Sujith Manoharan87df8952011-02-21 07:49:08 +05301636
Sujithfb9987d2010-03-17 14:25:25 +05301637 switch (action) {
1638 case IEEE80211_AMPDU_RX_START:
1639 break;
1640 case IEEE80211_AMPDU_RX_STOP:
1641 break;
1642 case IEEE80211_AMPDU_TX_START:
Sujithd7ca2132010-06-15 10:24:37 +05301643 ret = ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
1644 if (!ret)
1645 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1646 break;
Johannes Berg18b559d2012-07-18 13:51:25 +02001647 case IEEE80211_AMPDU_TX_STOP_CONT:
1648 case IEEE80211_AMPDU_TX_STOP_FLUSH:
1649 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
Sujithd7ca2132010-06-15 10:24:37 +05301650 ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
1651 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
Sujithfb9987d2010-03-17 14:25:25 +05301652 break;
1653 case IEEE80211_AMPDU_TX_OPERATIONAL:
1654 ista = (struct ath9k_htc_sta *) sta->drv_priv;
Sujith Manoharan658ef042011-04-13 11:25:00 +05301655 spin_lock_bh(&priv->tx.tx_lock);
Sujithfb9987d2010-03-17 14:25:25 +05301656 ista->tid_state[tid] = AGGR_OPERATIONAL;
Sujith Manoharan658ef042011-04-13 11:25:00 +05301657 spin_unlock_bh(&priv->tx.tx_lock);
Sujithfb9987d2010-03-17 14:25:25 +05301658 break;
1659 default:
Joe Perches38002762010-12-02 19:12:36 -08001660 ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n");
Sujithfb9987d2010-03-17 14:25:25 +05301661 }
1662
Sujith Manoharanc58ca5b2011-04-20 11:01:10 +05301663 ath9k_htc_ps_restore(priv);
Sujith Manoharan87df8952011-02-21 07:49:08 +05301664 mutex_unlock(&priv->mutex);
1665
Sujithd7ca2132010-06-15 10:24:37 +05301666 return ret;
Sujithfb9987d2010-03-17 14:25:25 +05301667}
1668
1669static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
1670{
1671 struct ath9k_htc_priv *priv = hw->priv;
1672
1673 mutex_lock(&priv->mutex);
1674 spin_lock_bh(&priv->beacon_lock);
Sujith Manoharand8a2c512012-06-25 13:54:41 +05301675 set_bit(OP_SCANNING, &priv->op_flags);
Sujithfb9987d2010-03-17 14:25:25 +05301676 spin_unlock_bh(&priv->beacon_lock);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301677 cancel_work_sync(&priv->ps_work);
Sujith Manoharana2362542011-02-21 07:49:38 +05301678 ath9k_htc_stop_ani(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301679 mutex_unlock(&priv->mutex);
1680}
1681
1682static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
1683{
1684 struct ath9k_htc_priv *priv = hw->priv;
1685
1686 mutex_lock(&priv->mutex);
1687 spin_lock_bh(&priv->beacon_lock);
Sujith Manoharand8a2c512012-06-25 13:54:41 +05301688 clear_bit(OP_SCANNING, &priv->op_flags);
Sujithfb9987d2010-03-17 14:25:25 +05301689 spin_unlock_bh(&priv->beacon_lock);
Sujith Manoharan7c277342011-02-21 07:48:39 +05301690 ath9k_htc_ps_wakeup(priv);
1691 ath9k_htc_vif_reconfig(priv);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301692 ath9k_htc_ps_restore(priv);
Sujithcb551df2010-06-01 15:14:12 +05301693 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301694}
1695
1696static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1697{
1698 return 0;
1699}
1700
1701static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
1702 u8 coverage_class)
1703{
1704 struct ath9k_htc_priv *priv = hw->priv;
1705
1706 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301707 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301708 priv->ah->coverage_class = coverage_class;
1709 ath9k_hw_init_global_settings(priv->ah);
Sujithcb551df2010-06-01 15:14:12 +05301710 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301711 mutex_unlock(&priv->mutex);
1712}
1713
Sujith Manoharane2186b72011-04-27 17:13:40 +05301714/*
1715 * Currently, this is used only for selecting the minimum rate
1716 * for management frames, rate selection for data frames remain
1717 * unaffected.
1718 */
1719static int ath9k_htc_set_bitrate_mask(struct ieee80211_hw *hw,
1720 struct ieee80211_vif *vif,
1721 const struct cfg80211_bitrate_mask *mask)
1722{
1723 struct ath9k_htc_priv *priv = hw->priv;
1724 struct ath_common *common = ath9k_hw_common(priv->ah);
1725 struct ath9k_htc_target_rate_mask tmask;
1726 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1727 int ret = 0;
1728 u8 cmd_rsp;
1729
1730 memset(&tmask, 0, sizeof(struct ath9k_htc_target_rate_mask));
1731
1732 tmask.vif_index = avp->index;
1733 tmask.band = IEEE80211_BAND_2GHZ;
1734 tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_2GHZ].legacy);
1735
1736 WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask);
1737 if (ret) {
1738 ath_err(common,
1739 "Unable to set 2G rate mask for "
1740 "interface at idx: %d\n", avp->index);
1741 goto out;
1742 }
1743
1744 tmask.band = IEEE80211_BAND_5GHZ;
1745 tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_5GHZ].legacy);
1746
1747 WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask);
1748 if (ret) {
1749 ath_err(common,
1750 "Unable to set 5G rate mask for "
1751 "interface at idx: %d\n", avp->index);
1752 goto out;
1753 }
1754
Joe Perchesd2182b62011-12-15 14:55:53 -08001755 ath_dbg(common, CONFIG, "Set bitrate masks: 0x%x, 0x%x\n",
Sujith Manoharane2186b72011-04-27 17:13:40 +05301756 mask->control[IEEE80211_BAND_2GHZ].legacy,
1757 mask->control[IEEE80211_BAND_5GHZ].legacy);
1758out:
1759 return ret;
1760}
1761
Mohammed Shafi Shajakhan5fa71982011-08-25 01:01:22 +05301762
1763static int ath9k_htc_get_stats(struct ieee80211_hw *hw,
1764 struct ieee80211_low_level_stats *stats)
1765{
1766 struct ath9k_htc_priv *priv = hw->priv;
1767 struct ath_hw *ah = priv->ah;
1768 struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats;
1769
1770 stats->dot11ACKFailureCount = mib_stats->ackrcv_bad;
1771 stats->dot11RTSFailureCount = mib_stats->rts_bad;
1772 stats->dot11FCSErrorCount = mib_stats->fcs_bad;
1773 stats->dot11RTSSuccessCount = mib_stats->rts_good;
1774
1775 return 0;
1776}
1777
Ben Greear156652b2013-06-19 14:02:14 -07001778struct base_eep_header *ath9k_htc_get_eeprom_base(struct ath9k_htc_priv *priv)
1779{
1780 struct base_eep_header *pBase = NULL;
1781 /*
1782 * This can be done since all the 3 EEPROM families have the
1783 * same base header upto a certain point, and we are interested in
1784 * the data only upto that point.
1785 */
1786
1787 if (AR_SREV_9271(priv->ah))
1788 pBase = (struct base_eep_header *)
1789 &priv->ah->eeprom.map4k.baseEepHeader;
1790 else if (priv->ah->hw_version.usbdev == AR9280_USB)
1791 pBase = (struct base_eep_header *)
1792 &priv->ah->eeprom.def.baseEepHeader;
1793 else if (priv->ah->hw_version.usbdev == AR9287_USB)
1794 pBase = (struct base_eep_header *)
1795 &priv->ah->eeprom.map9287.baseEepHeader;
1796 return pBase;
1797}
1798
1799
1800static int ath9k_htc_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant,
1801 u32 *rx_ant)
1802{
1803 struct ath9k_htc_priv *priv = hw->priv;
1804 struct base_eep_header *pBase = ath9k_htc_get_eeprom_base(priv);
1805 if (pBase) {
1806 *tx_ant = pBase->txMask;
1807 *rx_ant = pBase->rxMask;
1808 } else {
1809 *tx_ant = 0;
1810 *rx_ant = 0;
1811 }
1812 return 0;
1813}
1814
Sujithfb9987d2010-03-17 14:25:25 +05301815struct ieee80211_ops ath9k_htc_ops = {
1816 .tx = ath9k_htc_tx,
1817 .start = ath9k_htc_start,
1818 .stop = ath9k_htc_stop,
1819 .add_interface = ath9k_htc_add_interface,
1820 .remove_interface = ath9k_htc_remove_interface,
1821 .config = ath9k_htc_config,
1822 .configure_filter = ath9k_htc_configure_filter,
Sujithabd984e2010-05-18 15:26:04 +05301823 .sta_add = ath9k_htc_sta_add,
1824 .sta_remove = ath9k_htc_sta_remove,
Sujithfb9987d2010-03-17 14:25:25 +05301825 .conf_tx = ath9k_htc_conf_tx,
Antonio Quartulli69578022012-08-12 19:36:41 +02001826 .sta_rc_update = ath9k_htc_sta_rc_update,
Sujithfb9987d2010-03-17 14:25:25 +05301827 .bss_info_changed = ath9k_htc_bss_info_changed,
1828 .set_key = ath9k_htc_set_key,
1829 .get_tsf = ath9k_htc_get_tsf,
1830 .set_tsf = ath9k_htc_set_tsf,
1831 .reset_tsf = ath9k_htc_reset_tsf,
1832 .ampdu_action = ath9k_htc_ampdu_action,
1833 .sw_scan_start = ath9k_htc_sw_scan_start,
1834 .sw_scan_complete = ath9k_htc_sw_scan_complete,
1835 .set_rts_threshold = ath9k_htc_set_rts_threshold,
1836 .rfkill_poll = ath9k_htc_rfkill_poll_state,
1837 .set_coverage_class = ath9k_htc_set_coverage_class,
Sujith Manoharane2186b72011-04-27 17:13:40 +05301838 .set_bitrate_mask = ath9k_htc_set_bitrate_mask,
Mohammed Shafi Shajakhan5fa71982011-08-25 01:01:22 +05301839 .get_stats = ath9k_htc_get_stats,
Ben Greear156652b2013-06-19 14:02:14 -07001840 .get_antenna = ath9k_htc_get_antenna,
Ben Greear68185a42013-06-19 14:02:15 -07001841
1842#ifdef CONFIG_ATH9K_HTC_DEBUGFS
1843 .get_et_sset_count = ath9k_htc_get_et_sset_count,
1844 .get_et_stats = ath9k_htc_get_et_stats,
1845 .get_et_strings = ath9k_htc_get_et_strings,
1846#endif
Sujithfb9987d2010-03-17 14:25:25 +05301847};