blob: fe5debf0b7d72cbdc57578cf63b57772f02f9012 [file] [log] [blame]
Sujithfb9987d2010-03-17 14:25:25 +05301/*
2 * Copyright (c) 2010 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "htc.h"
18
19#ifdef CONFIG_ATH9K_HTC_DEBUGFS
20static struct dentry *ath9k_debugfs_root;
21#endif
22
23/*************/
24/* Utilities */
25/*************/
26
27static void ath_update_txpow(struct ath9k_htc_priv *priv)
28{
29 struct ath_hw *ah = priv->ah;
30 u32 txpow;
31
32 if (priv->curtxpow != priv->txpowlimit) {
33 ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit);
34 /* read back in case value is clamped */
35 ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
36 priv->curtxpow = txpow;
37 }
38}
39
40/* HACK Alert: Use 11NG for 2.4, use 11NA for 5 */
41static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
42 struct ath9k_channel *ichan)
43{
44 enum htc_phymode mode;
45
46 mode = HTC_MODE_AUTO;
47
48 switch (ichan->chanmode) {
49 case CHANNEL_G:
50 case CHANNEL_G_HT20:
51 case CHANNEL_G_HT40PLUS:
52 case CHANNEL_G_HT40MINUS:
53 mode = HTC_MODE_11NG;
54 break;
55 case CHANNEL_A:
56 case CHANNEL_A_HT20:
57 case CHANNEL_A_HT40PLUS:
58 case CHANNEL_A_HT40MINUS:
59 mode = HTC_MODE_11NA;
60 break;
61 default:
62 break;
63 }
64
65 return mode;
66}
67
Vivek Natarajanbde748a2010-04-05 14:48:05 +053068static bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
69 enum ath9k_power_mode mode)
70{
71 bool ret;
72
73 mutex_lock(&priv->htc_pm_lock);
74 ret = ath9k_hw_setpower(priv->ah, mode);
75 mutex_unlock(&priv->htc_pm_lock);
76
77 return ret;
78}
79
80void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv)
81{
82 mutex_lock(&priv->htc_pm_lock);
83 if (++priv->ps_usecount != 1)
84 goto unlock;
85 ath9k_hw_setpower(priv->ah, ATH9K_PM_AWAKE);
86
87unlock:
88 mutex_unlock(&priv->htc_pm_lock);
89}
90
91void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv)
92{
93 mutex_lock(&priv->htc_pm_lock);
94 if (--priv->ps_usecount != 0)
95 goto unlock;
96
Vivek Natarajan8a8572a2010-04-27 13:05:37 +053097 if (priv->ps_idle)
98 ath9k_hw_setpower(priv->ah, ATH9K_PM_FULL_SLEEP);
99 else if (priv->ps_enabled)
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530100 ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +0530101
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530102unlock:
103 mutex_unlock(&priv->htc_pm_lock);
104}
105
106void ath9k_ps_work(struct work_struct *work)
107{
108 struct ath9k_htc_priv *priv =
109 container_of(work, struct ath9k_htc_priv,
110 ps_work);
111 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
112
113 /* The chip wakes up after receiving the first beacon
114 while network sleep is enabled. For the driver to
115 be in sync with the hw, set the chip to awake and
116 only then set it to sleep.
117 */
118 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
119}
120
Sujithfb9987d2010-03-17 14:25:25 +0530121static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
122 struct ieee80211_hw *hw,
123 struct ath9k_channel *hchan)
124{
125 struct ath_hw *ah = priv->ah;
126 struct ath_common *common = ath9k_hw_common(ah);
127 struct ieee80211_conf *conf = &common->hw->conf;
128 bool fastcc = true;
129 struct ieee80211_channel *channel = hw->conf.channel;
130 enum htc_phymode mode;
Sujith7f1f5a02010-04-16 11:54:03 +0530131 __be16 htc_mode;
Sujithfb9987d2010-03-17 14:25:25 +0530132 u8 cmd_rsp;
133 int ret;
134
135 if (priv->op_flags & OP_INVALID)
136 return -EIO;
137
138 if (priv->op_flags & OP_FULL_RESET)
139 fastcc = false;
140
141 /* Fiddle around with fastcc later on, for now just use full reset */
142 fastcc = false;
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530143 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530144 htc_stop(priv->htc);
145 WMI_CMD(WMI_DISABLE_INTR_CMDID);
146 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
147 WMI_CMD(WMI_STOP_RECV_CMDID);
148
149 ath_print(common, ATH_DBG_CONFIG,
150 "(%u MHz) -> (%u MHz), HT: %d, HT40: %d\n",
151 priv->ah->curchan->channel,
152 channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf));
153
154 ret = ath9k_hw_reset(ah, hchan, fastcc);
155 if (ret) {
156 ath_print(common, ATH_DBG_FATAL,
157 "Unable to reset channel (%u Mhz) "
158 "reset status %d\n", channel->center_freq, ret);
159 goto err;
160 }
161
162 ath_update_txpow(priv);
163
164 WMI_CMD(WMI_START_RECV_CMDID);
165 if (ret)
166 goto err;
167
168 ath9k_host_rx_init(priv);
169
170 mode = ath9k_htc_get_curmode(priv, hchan);
171 htc_mode = cpu_to_be16(mode);
172 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
173 if (ret)
174 goto err;
175
176 WMI_CMD(WMI_ENABLE_INTR_CMDID);
177 if (ret)
178 goto err;
179
180 htc_start(priv->htc);
181
182 priv->op_flags &= ~OP_FULL_RESET;
183err:
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530184 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530185 return ret;
186}
187
188static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
189{
190 struct ath_common *common = ath9k_hw_common(priv->ah);
191 struct ath9k_htc_target_vif hvif;
192 int ret = 0;
193 u8 cmd_rsp;
194
195 if (priv->nvifs > 0)
196 return -ENOBUFS;
197
198 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
199 memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
200
201 hvif.opmode = cpu_to_be32(HTC_M_MONITOR);
202 priv->ah->opmode = NL80211_IFTYPE_MONITOR;
203 hvif.index = priv->nvifs;
204
205 WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
206 if (ret)
207 return ret;
208
209 priv->nvifs++;
210 return 0;
211}
212
213static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
214{
215 struct ath_common *common = ath9k_hw_common(priv->ah);
216 struct ath9k_htc_target_vif hvif;
217 int ret = 0;
218 u8 cmd_rsp;
219
220 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
221 memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
222 hvif.index = 0; /* Should do for now */
223 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
224 priv->nvifs--;
225
226 return ret;
227}
228
229static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
230 struct ieee80211_vif *vif,
231 struct ieee80211_sta *sta)
232{
233 struct ath_common *common = ath9k_hw_common(priv->ah);
234 struct ath9k_htc_target_sta tsta;
235 struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
236 struct ath9k_htc_sta *ista;
237 int ret;
238 u8 cmd_rsp;
239
240 if (priv->nstations >= ATH9K_HTC_MAX_STA)
241 return -ENOBUFS;
242
243 memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta));
244
245 if (sta) {
246 ista = (struct ath9k_htc_sta *) sta->drv_priv;
247 memcpy(&tsta.macaddr, sta->addr, ETH_ALEN);
248 memcpy(&tsta.bssid, common->curbssid, ETH_ALEN);
249 tsta.associd = common->curaid;
250 tsta.is_vif_sta = 0;
251 tsta.valid = true;
252 ista->index = priv->nstations;
253 } else {
254 memcpy(&tsta.macaddr, vif->addr, ETH_ALEN);
255 tsta.is_vif_sta = 1;
256 }
257
258 tsta.sta_index = priv->nstations;
259 tsta.vif_index = avp->index;
260 tsta.maxampdu = 0xffff;
261 if (sta && sta->ht_cap.ht_supported)
262 tsta.flags = cpu_to_be16(ATH_HTC_STA_HT);
263
264 WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
265 if (ret) {
266 if (sta)
267 ath_print(common, ATH_DBG_FATAL,
268 "Unable to add station entry for: %pM\n", sta->addr);
269 return ret;
270 }
271
272 if (sta)
273 ath_print(common, ATH_DBG_CONFIG,
274 "Added a station entry for: %pM (idx: %d)\n",
275 sta->addr, tsta.sta_index);
276
277 priv->nstations++;
278 return 0;
279}
280
281static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
282 struct ieee80211_vif *vif,
283 struct ieee80211_sta *sta)
284{
285 struct ath_common *common = ath9k_hw_common(priv->ah);
286 struct ath9k_htc_sta *ista;
287 int ret;
288 u8 cmd_rsp, sta_idx;
289
290 if (sta) {
291 ista = (struct ath9k_htc_sta *) sta->drv_priv;
292 sta_idx = ista->index;
293 } else {
294 sta_idx = 0;
295 }
296
297 WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx);
298 if (ret) {
299 if (sta)
300 ath_print(common, ATH_DBG_FATAL,
301 "Unable to remove station entry for: %pM\n",
302 sta->addr);
303 return ret;
304 }
305
306 if (sta)
307 ath_print(common, ATH_DBG_CONFIG,
308 "Removed a station entry for: %pM (idx: %d)\n",
309 sta->addr, sta_idx);
310
311 priv->nstations--;
312 return 0;
313}
314
315static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
316{
317 struct ath9k_htc_cap_target tcap;
318 int ret;
319 u8 cmd_rsp;
320
321 memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target));
322
323 /* FIXME: Values are hardcoded */
324 tcap.flags = 0x240c40;
325 tcap.flags_ext = 0x80601000;
326 tcap.ampdu_limit = 0xffff0000;
327 tcap.ampdu_subframes = 20;
328 tcap.tx_chainmask_legacy = 1;
329 tcap.protmode = 1;
330 tcap.tx_chainmask = 1;
331
332 WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap);
333
334 return ret;
335}
336
Sujith0d425a72010-05-17 12:01:16 +0530337static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv,
338 struct ieee80211_sta *sta,
339 struct ath9k_htc_target_rate *trate)
Sujithfb9987d2010-03-17 14:25:25 +0530340{
Sujithfb9987d2010-03-17 14:25:25 +0530341 struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
342 struct ieee80211_supported_band *sband;
Sujithfb9987d2010-03-17 14:25:25 +0530343 u32 caps = 0;
Sujith0d425a72010-05-17 12:01:16 +0530344 int i, j;
Sujithfb9987d2010-03-17 14:25:25 +0530345
346 /* Only 2GHz is supported */
347 sband = priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
348
349 for (i = 0, j = 0; i < sband->n_bitrates; i++) {
350 if (sta->supp_rates[sband->band] & BIT(i)) {
Sujith0d425a72010-05-17 12:01:16 +0530351 trate->rates.legacy_rates.rs_rates[j]
Sujithfb9987d2010-03-17 14:25:25 +0530352 = (sband->bitrates[i].bitrate * 2) / 10;
353 j++;
354 }
355 }
Sujith0d425a72010-05-17 12:01:16 +0530356 trate->rates.legacy_rates.rs_nrates = j;
Sujithfb9987d2010-03-17 14:25:25 +0530357
358 if (sta->ht_cap.ht_supported) {
359 for (i = 0, j = 0; i < 77; i++) {
360 if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
Sujith0d425a72010-05-17 12:01:16 +0530361 trate->rates.ht_rates.rs_rates[j++] = i;
Sujithfb9987d2010-03-17 14:25:25 +0530362 if (j == ATH_HTC_RATE_MAX)
363 break;
364 }
Sujith0d425a72010-05-17 12:01:16 +0530365 trate->rates.ht_rates.rs_nrates = j;
Sujithfb9987d2010-03-17 14:25:25 +0530366
367 caps = WLAN_RC_HT_FLAG;
368 if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
369 caps |= WLAN_RC_40_FLAG;
370 if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
371 caps |= WLAN_RC_SGI_FLAG;
372
373 }
374
Sujith0d425a72010-05-17 12:01:16 +0530375 trate->sta_index = ista->index;
376 trate->isnew = 1;
377 trate->capflags = cpu_to_be32(caps);
378}
Sujithfb9987d2010-03-17 14:25:25 +0530379
Sujith0d425a72010-05-17 12:01:16 +0530380static int ath9k_htc_send_rate_cmd(struct ath9k_htc_priv *priv,
381 struct ath9k_htc_target_rate *trate)
382{
383 struct ath_common *common = ath9k_hw_common(priv->ah);
384 int ret;
385 u8 cmd_rsp;
386
387 WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, trate);
Sujithfb9987d2010-03-17 14:25:25 +0530388 if (ret) {
389 ath_print(common, ATH_DBG_FATAL,
390 "Unable to initialize Rate information on target\n");
Sujithfb9987d2010-03-17 14:25:25 +0530391 }
392
Sujith0d425a72010-05-17 12:01:16 +0530393 return ret;
Sujithfb9987d2010-03-17 14:25:25 +0530394}
395
Sujith0d425a72010-05-17 12:01:16 +0530396static void ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
397 struct ieee80211_sta *sta)
Sujithfb9987d2010-03-17 14:25:25 +0530398{
Sujithfb9987d2010-03-17 14:25:25 +0530399 struct ath_common *common = ath9k_hw_common(priv->ah);
Sujith0d425a72010-05-17 12:01:16 +0530400 struct ath9k_htc_target_rate trate;
Sujithfb9987d2010-03-17 14:25:25 +0530401 int ret;
Sujithfb9987d2010-03-17 14:25:25 +0530402
Sujith0d425a72010-05-17 12:01:16 +0530403 memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
404 ath9k_htc_setup_rate(priv, sta, &trate);
405 ret = ath9k_htc_send_rate_cmd(priv, &trate);
406 if (!ret)
407 ath_print(common, ATH_DBG_CONFIG,
408 "Updated target sta: %pM, rate caps: 0x%X\n",
409 sta->addr, be32_to_cpu(trate.capflags));
Sujithfb9987d2010-03-17 14:25:25 +0530410}
411
412static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
413 struct ieee80211_vif *vif,
414 u8 *sta_addr, u8 tid, bool oper)
415{
416 struct ath_common *common = ath9k_hw_common(priv->ah);
417 struct ath9k_htc_target_aggr aggr;
418 struct ieee80211_sta *sta = NULL;
Dan Carpenter277a64d2010-05-08 18:23:20 +0200419 struct ath9k_htc_sta *ista;
Sujithfb9987d2010-03-17 14:25:25 +0530420 int ret = 0;
421 u8 cmd_rsp;
422
Dan Carpenter0730d112010-05-08 18:24:02 +0200423 if (tid >= ATH9K_HTC_MAX_TID)
Sujithfb9987d2010-03-17 14:25:25 +0530424 return -EINVAL;
425
Sujithfb9987d2010-03-17 14:25:25 +0530426 memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
427
Sujithef98c3c2010-03-29 16:07:11 +0530428 rcu_read_lock();
429
430 /* Check if we are able to retrieve the station */
431 sta = ieee80211_find_sta(vif, sta_addr);
432 if (!sta) {
433 rcu_read_unlock();
434 return -EINVAL;
435 }
436
437 ista = (struct ath9k_htc_sta *) sta->drv_priv;
Sujithfb9987d2010-03-17 14:25:25 +0530438
439 if (oper)
440 ista->tid_state[tid] = AGGR_START;
441 else
442 ista->tid_state[tid] = AGGR_STOP;
443
Sujithef98c3c2010-03-29 16:07:11 +0530444 aggr.sta_index = ista->index;
445
446 rcu_read_unlock();
447
448 aggr.tidno = tid;
449 aggr.aggr_enable = oper;
450
Sujithfb9987d2010-03-17 14:25:25 +0530451 WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
452 if (ret)
453 ath_print(common, ATH_DBG_CONFIG,
454 "Unable to %s TX aggregation for (%pM, %d)\n",
455 (oper) ? "start" : "stop", sta->addr, tid);
456 else
457 ath_print(common, ATH_DBG_CONFIG,
458 "%s aggregation for (%pM, %d)\n",
459 (oper) ? "Starting" : "Stopping", sta->addr, tid);
460
461 return ret;
462}
463
464void ath9k_htc_aggr_work(struct work_struct *work)
465{
466 int ret = 0;
467 struct ath9k_htc_priv *priv =
468 container_of(work, struct ath9k_htc_priv,
469 ath9k_aggr_work.work);
470 struct ath9k_htc_aggr_work *wk = &priv->aggr_work;
471
472 mutex_lock(&wk->mutex);
473
474 switch (wk->action) {
475 case IEEE80211_AMPDU_TX_START:
476 ret = ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
477 wk->tid, true);
478 if (!ret)
479 ieee80211_start_tx_ba_cb(wk->vif, wk->sta_addr,
480 wk->tid);
481 break;
482 case IEEE80211_AMPDU_TX_STOP:
483 ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
484 wk->tid, false);
485 ieee80211_stop_tx_ba_cb(wk->vif, wk->sta_addr, wk->tid);
486 break;
487 default:
488 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
489 "Unknown AMPDU action\n");
490 }
491
492 mutex_unlock(&wk->mutex);
493}
494
495/*********/
496/* DEBUG */
497/*********/
498
499#ifdef CONFIG_ATH9K_HTC_DEBUGFS
500
501static int ath9k_debugfs_open(struct inode *inode, struct file *file)
502{
503 file->private_data = inode->i_private;
504 return 0;
505}
506
507static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
508 size_t count, loff_t *ppos)
509{
510 struct ath9k_htc_priv *priv =
511 (struct ath9k_htc_priv *) file->private_data;
512 struct ath9k_htc_target_stats cmd_rsp;
513 char buf[512];
514 unsigned int len = 0;
515 int ret = 0;
516
517 memset(&cmd_rsp, 0, sizeof(cmd_rsp));
518
519 WMI_CMD(WMI_TGT_STATS_CMDID);
520 if (ret)
521 return -EINVAL;
522
523
524 len += snprintf(buf + len, sizeof(buf) - len,
525 "%19s : %10u\n", "TX Short Retries",
526 be32_to_cpu(cmd_rsp.tx_shortretry));
527 len += snprintf(buf + len, sizeof(buf) - len,
528 "%19s : %10u\n", "TX Long Retries",
529 be32_to_cpu(cmd_rsp.tx_longretry));
530 len += snprintf(buf + len, sizeof(buf) - len,
531 "%19s : %10u\n", "TX Xretries",
532 be32_to_cpu(cmd_rsp.tx_xretries));
533 len += snprintf(buf + len, sizeof(buf) - len,
534 "%19s : %10u\n", "TX Unaggr. Xretries",
535 be32_to_cpu(cmd_rsp.ht_txunaggr_xretry));
536 len += snprintf(buf + len, sizeof(buf) - len,
537 "%19s : %10u\n", "TX Xretries (HT)",
538 be32_to_cpu(cmd_rsp.ht_tx_xretries));
539 len += snprintf(buf + len, sizeof(buf) - len,
540 "%19s : %10u\n", "TX Rate", priv->debug.txrate);
541
542 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
543}
544
545static const struct file_operations fops_tgt_stats = {
546 .read = read_file_tgt_stats,
547 .open = ath9k_debugfs_open,
548 .owner = THIS_MODULE
549};
550
551static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
552 size_t count, loff_t *ppos)
553{
554 struct ath9k_htc_priv *priv =
555 (struct ath9k_htc_priv *) file->private_data;
556 char buf[512];
557 unsigned int len = 0;
558
559 len += snprintf(buf + len, sizeof(buf) - len,
560 "%20s : %10u\n", "Buffers queued",
561 priv->debug.tx_stats.buf_queued);
562 len += snprintf(buf + len, sizeof(buf) - len,
563 "%20s : %10u\n", "Buffers completed",
564 priv->debug.tx_stats.buf_completed);
565 len += snprintf(buf + len, sizeof(buf) - len,
566 "%20s : %10u\n", "SKBs queued",
567 priv->debug.tx_stats.skb_queued);
568 len += snprintf(buf + len, sizeof(buf) - len,
569 "%20s : %10u\n", "SKBs completed",
570 priv->debug.tx_stats.skb_completed);
Sujitheac8e382010-04-16 11:54:00 +0530571 len += snprintf(buf + len, sizeof(buf) - len,
572 "%20s : %10u\n", "SKBs dropped",
573 priv->debug.tx_stats.skb_dropped);
Sujithfb9987d2010-03-17 14:25:25 +0530574
Sujith2edb4582010-05-14 11:18:54 +0530575 len += snprintf(buf + len, sizeof(buf) - len,
576 "%20s : %10u\n", "BE queued",
577 priv->debug.tx_stats.queue_stats[WME_AC_BE]);
578 len += snprintf(buf + len, sizeof(buf) - len,
579 "%20s : %10u\n", "BK queued",
580 priv->debug.tx_stats.queue_stats[WME_AC_BK]);
581 len += snprintf(buf + len, sizeof(buf) - len,
582 "%20s : %10u\n", "VI queued",
583 priv->debug.tx_stats.queue_stats[WME_AC_VI]);
584 len += snprintf(buf + len, sizeof(buf) - len,
585 "%20s : %10u\n", "VO queued",
586 priv->debug.tx_stats.queue_stats[WME_AC_VO]);
587
Sujithfb9987d2010-03-17 14:25:25 +0530588 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
589}
590
591static const struct file_operations fops_xmit = {
592 .read = read_file_xmit,
593 .open = ath9k_debugfs_open,
594 .owner = THIS_MODULE
595};
596
597static ssize_t read_file_recv(struct file *file, char __user *user_buf,
598 size_t count, loff_t *ppos)
599{
600 struct ath9k_htc_priv *priv =
601 (struct ath9k_htc_priv *) file->private_data;
602 char buf[512];
603 unsigned int len = 0;
604
605 len += snprintf(buf + len, sizeof(buf) - len,
606 "%20s : %10u\n", "SKBs allocated",
607 priv->debug.rx_stats.skb_allocated);
608 len += snprintf(buf + len, sizeof(buf) - len,
609 "%20s : %10u\n", "SKBs completed",
610 priv->debug.rx_stats.skb_completed);
611 len += snprintf(buf + len, sizeof(buf) - len,
612 "%20s : %10u\n", "SKBs Dropped",
613 priv->debug.rx_stats.skb_dropped);
614
615 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
616}
617
618static const struct file_operations fops_recv = {
619 .read = read_file_recv,
620 .open = ath9k_debugfs_open,
621 .owner = THIS_MODULE
622};
623
Sujithe1572c52010-03-24 13:42:13 +0530624int ath9k_htc_init_debug(struct ath_hw *ah)
Sujithfb9987d2010-03-17 14:25:25 +0530625{
626 struct ath_common *common = ath9k_hw_common(ah);
627 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
628
629 if (!ath9k_debugfs_root)
630 return -ENOENT;
631
632 priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy),
633 ath9k_debugfs_root);
634 if (!priv->debug.debugfs_phy)
635 goto err;
636
637 priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR,
638 priv->debug.debugfs_phy,
639 priv, &fops_tgt_stats);
640 if (!priv->debug.debugfs_tgt_stats)
641 goto err;
642
643
644 priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR,
645 priv->debug.debugfs_phy,
646 priv, &fops_xmit);
647 if (!priv->debug.debugfs_xmit)
648 goto err;
649
650 priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR,
651 priv->debug.debugfs_phy,
652 priv, &fops_recv);
653 if (!priv->debug.debugfs_recv)
654 goto err;
655
656 return 0;
657
658err:
Sujithe1572c52010-03-24 13:42:13 +0530659 ath9k_htc_exit_debug(ah);
Sujithfb9987d2010-03-17 14:25:25 +0530660 return -ENOMEM;
661}
662
Sujithe1572c52010-03-24 13:42:13 +0530663void ath9k_htc_exit_debug(struct ath_hw *ah)
Sujithfb9987d2010-03-17 14:25:25 +0530664{
665 struct ath_common *common = ath9k_hw_common(ah);
666 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
667
668 debugfs_remove(priv->debug.debugfs_recv);
669 debugfs_remove(priv->debug.debugfs_xmit);
670 debugfs_remove(priv->debug.debugfs_tgt_stats);
671 debugfs_remove(priv->debug.debugfs_phy);
672}
673
Sujithe1572c52010-03-24 13:42:13 +0530674int ath9k_htc_debug_create_root(void)
Sujithfb9987d2010-03-17 14:25:25 +0530675{
676 ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
677 if (!ath9k_debugfs_root)
678 return -ENOENT;
679
680 return 0;
681}
682
Sujithe1572c52010-03-24 13:42:13 +0530683void ath9k_htc_debug_remove_root(void)
Sujithfb9987d2010-03-17 14:25:25 +0530684{
685 debugfs_remove(ath9k_debugfs_root);
686 ath9k_debugfs_root = NULL;
687}
688
689#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
690
691/*******/
692/* ANI */
693/*******/
694
695static void ath_start_ani(struct ath9k_htc_priv *priv)
696{
697 struct ath_common *common = ath9k_hw_common(priv->ah);
698 unsigned long timestamp = jiffies_to_msecs(jiffies);
699
700 common->ani.longcal_timer = timestamp;
701 common->ani.shortcal_timer = timestamp;
702 common->ani.checkani_timer = timestamp;
703
704 ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
705 msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
706}
707
708void ath9k_ani_work(struct work_struct *work)
709{
710 struct ath9k_htc_priv *priv =
711 container_of(work, struct ath9k_htc_priv,
712 ath9k_ani_work.work);
713 struct ath_hw *ah = priv->ah;
714 struct ath_common *common = ath9k_hw_common(ah);
715 bool longcal = false;
716 bool shortcal = false;
717 bool aniflag = false;
718 unsigned int timestamp = jiffies_to_msecs(jiffies);
719 u32 cal_interval, short_cal_interval;
720
721 short_cal_interval = ATH_STA_SHORT_CALINTERVAL;
722
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530723 /* Only calibrate if awake */
724 if (ah->power_mode != ATH9K_PM_AWAKE)
725 goto set_timer;
726
Sujithfb9987d2010-03-17 14:25:25 +0530727 /* Long calibration runs independently of short calibration. */
728 if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
729 longcal = true;
730 ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
731 common->ani.longcal_timer = timestamp;
732 }
733
734 /* Short calibration applies only while caldone is false */
735 if (!common->ani.caldone) {
736 if ((timestamp - common->ani.shortcal_timer) >=
737 short_cal_interval) {
738 shortcal = true;
739 ath_print(common, ATH_DBG_ANI,
740 "shortcal @%lu\n", jiffies);
741 common->ani.shortcal_timer = timestamp;
742 common->ani.resetcal_timer = timestamp;
743 }
744 } else {
745 if ((timestamp - common->ani.resetcal_timer) >=
746 ATH_RESTART_CALINTERVAL) {
747 common->ani.caldone = ath9k_hw_reset_calvalid(ah);
748 if (common->ani.caldone)
749 common->ani.resetcal_timer = timestamp;
750 }
751 }
752
753 /* Verify whether we must check ANI */
754 if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
755 aniflag = true;
756 common->ani.checkani_timer = timestamp;
757 }
758
759 /* Skip all processing if there's nothing to do. */
760 if (longcal || shortcal || aniflag) {
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530761
762 ath9k_htc_ps_wakeup(priv);
763
Sujithfb9987d2010-03-17 14:25:25 +0530764 /* Call ANI routine if necessary */
765 if (aniflag)
766 ath9k_hw_ani_monitor(ah, ah->curchan);
767
768 /* Perform calibration if necessary */
769 if (longcal || shortcal) {
770 common->ani.caldone =
771 ath9k_hw_calibrate(ah, ah->curchan,
772 common->rx_chainmask,
773 longcal);
774
775 if (longcal)
776 common->ani.noise_floor =
777 ath9k_hw_getchan_noise(ah, ah->curchan);
778
779 ath_print(common, ATH_DBG_ANI,
780 " calibrate chan %u/%x nf: %d\n",
781 ah->curchan->channel,
782 ah->curchan->channelFlags,
783 common->ani.noise_floor);
784 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530785
786 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530787 }
788
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530789set_timer:
Sujithfb9987d2010-03-17 14:25:25 +0530790 /*
791 * Set timer interval based on previous results.
792 * The interval must be the shortest necessary to satisfy ANI,
793 * short calibration and long calibration.
794 */
795 cal_interval = ATH_LONG_CALINTERVAL;
796 if (priv->ah->config.enable_ani)
797 cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
798 if (!common->ani.caldone)
799 cal_interval = min(cal_interval, (u32)short_cal_interval);
800
801 ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
802 msecs_to_jiffies(cal_interval));
803}
804
805/*******/
806/* LED */
807/*******/
808
809static void ath9k_led_blink_work(struct work_struct *work)
810{
811 struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
812 ath9k_led_blink_work.work);
813
814 if (!(priv->op_flags & OP_LED_ASSOCIATED))
815 return;
816
817 if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
818 (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
819 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
820 else
821 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
822 (priv->op_flags & OP_LED_ON) ? 1 : 0);
823
824 ieee80211_queue_delayed_work(priv->hw,
825 &priv->ath9k_led_blink_work,
826 (priv->op_flags & OP_LED_ON) ?
827 msecs_to_jiffies(priv->led_off_duration) :
828 msecs_to_jiffies(priv->led_on_duration));
829
830 priv->led_on_duration = priv->led_on_cnt ?
831 max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
832 ATH_LED_ON_DURATION_IDLE;
833 priv->led_off_duration = priv->led_off_cnt ?
834 max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
835 ATH_LED_OFF_DURATION_IDLE;
836 priv->led_on_cnt = priv->led_off_cnt = 0;
837
838 if (priv->op_flags & OP_LED_ON)
839 priv->op_flags &= ~OP_LED_ON;
840 else
841 priv->op_flags |= OP_LED_ON;
842}
843
844static void ath9k_led_brightness_work(struct work_struct *work)
845{
846 struct ath_led *led = container_of(work, struct ath_led,
847 brightness_work.work);
848 struct ath9k_htc_priv *priv = led->priv;
849
850 switch (led->brightness) {
851 case LED_OFF:
852 if (led->led_type == ATH_LED_ASSOC ||
853 led->led_type == ATH_LED_RADIO) {
854 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
855 (led->led_type == ATH_LED_RADIO));
856 priv->op_flags &= ~OP_LED_ASSOCIATED;
857 if (led->led_type == ATH_LED_RADIO)
858 priv->op_flags &= ~OP_LED_ON;
859 } else {
860 priv->led_off_cnt++;
861 }
862 break;
863 case LED_FULL:
864 if (led->led_type == ATH_LED_ASSOC) {
865 priv->op_flags |= OP_LED_ASSOCIATED;
866 ieee80211_queue_delayed_work(priv->hw,
867 &priv->ath9k_led_blink_work, 0);
868 } else if (led->led_type == ATH_LED_RADIO) {
869 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
870 priv->op_flags |= OP_LED_ON;
871 } else {
872 priv->led_on_cnt++;
873 }
874 break;
875 default:
876 break;
877 }
878}
879
880static void ath9k_led_brightness(struct led_classdev *led_cdev,
881 enum led_brightness brightness)
882{
883 struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
884 struct ath9k_htc_priv *priv = led->priv;
885
886 led->brightness = brightness;
887 if (!(priv->op_flags & OP_LED_DEINIT))
888 ieee80211_queue_delayed_work(priv->hw,
889 &led->brightness_work, 0);
890}
891
892static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
893{
894 cancel_delayed_work_sync(&priv->radio_led.brightness_work);
895 cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
896 cancel_delayed_work_sync(&priv->tx_led.brightness_work);
897 cancel_delayed_work_sync(&priv->rx_led.brightness_work);
898}
899
900static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
901 char *trigger)
902{
903 int ret;
904
905 led->priv = priv;
906 led->led_cdev.name = led->name;
907 led->led_cdev.default_trigger = trigger;
908 led->led_cdev.brightness_set = ath9k_led_brightness;
909
910 ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
911 if (ret)
912 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
913 "Failed to register led:%s", led->name);
914 else
915 led->registered = 1;
916
917 INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
918
919 return ret;
920}
921
922static void ath9k_unregister_led(struct ath_led *led)
923{
924 if (led->registered) {
925 led_classdev_unregister(&led->led_cdev);
926 led->registered = 0;
927 }
928}
929
930void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
931{
932 priv->op_flags |= OP_LED_DEINIT;
933 ath9k_unregister_led(&priv->assoc_led);
934 priv->op_flags &= ~OP_LED_ASSOCIATED;
935 ath9k_unregister_led(&priv->tx_led);
936 ath9k_unregister_led(&priv->rx_led);
937 ath9k_unregister_led(&priv->radio_led);
Sujithfb9987d2010-03-17 14:25:25 +0530938}
939
940void ath9k_init_leds(struct ath9k_htc_priv *priv)
941{
942 char *trigger;
943 int ret;
944
945 if (AR_SREV_9287(priv->ah))
946 priv->ah->led_pin = ATH_LED_PIN_9287;
947 else if (AR_SREV_9271(priv->ah))
948 priv->ah->led_pin = ATH_LED_PIN_9271;
949 else
950 priv->ah->led_pin = ATH_LED_PIN_DEF;
951
952 /* Configure gpio 1 for output */
953 ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
954 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
955 /* LED off, active low */
956 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
957
958 INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
959
960 trigger = ieee80211_get_radio_led_name(priv->hw);
961 snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
962 "ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
963 ret = ath9k_register_led(priv, &priv->radio_led, trigger);
964 priv->radio_led.led_type = ATH_LED_RADIO;
965 if (ret)
966 goto fail;
967
968 trigger = ieee80211_get_assoc_led_name(priv->hw);
969 snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
970 "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
971 ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
972 priv->assoc_led.led_type = ATH_LED_ASSOC;
973 if (ret)
974 goto fail;
975
976 trigger = ieee80211_get_tx_led_name(priv->hw);
977 snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
978 "ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
979 ret = ath9k_register_led(priv, &priv->tx_led, trigger);
980 priv->tx_led.led_type = ATH_LED_TX;
981 if (ret)
982 goto fail;
983
984 trigger = ieee80211_get_rx_led_name(priv->hw);
985 snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
986 "ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
987 ret = ath9k_register_led(priv, &priv->rx_led, trigger);
988 priv->rx_led.led_type = ATH_LED_RX;
989 if (ret)
990 goto fail;
991
992 priv->op_flags &= ~OP_LED_DEINIT;
993
994 return;
995
996fail:
997 cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
998 ath9k_deinit_leds(priv);
999}
1000
1001/*******************/
1002/* Rfkill */
1003/*******************/
1004
1005static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
1006{
1007 return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
1008 priv->ah->rfkill_polarity;
1009}
1010
1011static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
1012{
1013 struct ath9k_htc_priv *priv = hw->priv;
1014 bool blocked = !!ath_is_rfkill_set(priv);
1015
1016 wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
1017}
1018
1019void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
1020{
1021 if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
1022 wiphy_rfkill_start_polling(priv->hw->wiphy);
1023}
1024
1025/**********************/
1026/* mac80211 Callbacks */
1027/**********************/
1028
1029static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1030{
1031 struct ieee80211_hdr *hdr;
1032 struct ath9k_htc_priv *priv = hw->priv;
Sujith7757dfe2010-03-29 16:07:17 +05301033 int padpos, padsize, ret;
Sujithfb9987d2010-03-17 14:25:25 +05301034
1035 hdr = (struct ieee80211_hdr *) skb->data;
1036
1037 /* Add the padding after the header if this is not already done */
1038 padpos = ath9k_cmn_padpos(hdr->frame_control);
1039 padsize = padpos & 3;
1040 if (padsize && skb->len > padpos) {
1041 if (skb_headroom(skb) < padsize)
1042 return -1;
1043 skb_push(skb, padsize);
1044 memmove(skb->data, skb->data + padsize, padpos);
1045 }
1046
Sujith7757dfe2010-03-29 16:07:17 +05301047 ret = ath9k_htc_tx_start(priv, skb);
1048 if (ret != 0) {
1049 if (ret == -ENOMEM) {
1050 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1051 "Stopping TX queues\n");
1052 ieee80211_stop_queues(hw);
1053 spin_lock_bh(&priv->tx_lock);
1054 priv->tx_queues_stop = true;
1055 spin_unlock_bh(&priv->tx_lock);
1056 } else {
1057 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1058 "Tx failed");
1059 }
Sujithfb9987d2010-03-17 14:25:25 +05301060 goto fail_tx;
1061 }
1062
1063 return 0;
1064
1065fail_tx:
1066 dev_kfree_skb_any(skb);
1067 return 0;
1068}
1069
Sujith2ff65752010-05-07 13:37:57 +05301070static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led)
Sujithfb9987d2010-03-17 14:25:25 +05301071{
1072 struct ath9k_htc_priv *priv = hw->priv;
1073 struct ath_hw *ah = priv->ah;
1074 struct ath_common *common = ath9k_hw_common(ah);
1075 struct ieee80211_channel *curchan = hw->conf.channel;
1076 struct ath9k_channel *init_channel;
1077 int ret = 0;
1078 enum htc_phymode mode;
Sujith7f1f5a02010-04-16 11:54:03 +05301079 __be16 htc_mode;
Sujithfb9987d2010-03-17 14:25:25 +05301080 u8 cmd_rsp;
1081
1082 ath_print(common, ATH_DBG_CONFIG,
1083 "Starting driver with initial channel: %d MHz\n",
1084 curchan->center_freq);
1085
Sujithfb9987d2010-03-17 14:25:25 +05301086 /* setup initial channel */
1087 init_channel = ath9k_cmn_get_curchannel(hw, ah);
1088
1089 /* Reset SERDES registers */
1090 ath9k_hw_configpcipowersave(ah, 0, 0);
1091
1092 ath9k_hw_htc_resetinit(ah);
1093 ret = ath9k_hw_reset(ah, init_channel, false);
1094 if (ret) {
1095 ath_print(common, ATH_DBG_FATAL,
1096 "Unable to reset hardware; reset status %d "
1097 "(freq %u MHz)\n", ret, curchan->center_freq);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301098 return ret;
Sujithfb9987d2010-03-17 14:25:25 +05301099 }
1100
1101 ath_update_txpow(priv);
1102
1103 mode = ath9k_htc_get_curmode(priv, init_channel);
1104 htc_mode = cpu_to_be16(mode);
1105 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
Sujithfb9987d2010-03-17 14:25:25 +05301106 WMI_CMD(WMI_ATH_INIT_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301107 WMI_CMD(WMI_START_RECV_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301108
1109 ath9k_host_rx_init(priv);
1110
1111 priv->op_flags &= ~OP_INVALID;
1112 htc_start(priv->htc);
1113
Sujith7757dfe2010-03-29 16:07:17 +05301114 spin_lock_bh(&priv->tx_lock);
1115 priv->tx_queues_stop = false;
1116 spin_unlock_bh(&priv->tx_lock);
1117
Sujith2ff65752010-05-07 13:37:57 +05301118 if (led) {
1119 /* Enable LED */
1120 ath9k_hw_cfg_output(ah, ah->led_pin,
1121 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
1122 ath9k_hw_set_gpio(ah, ah->led_pin, 0);
1123 }
1124
Sujith7757dfe2010-03-29 16:07:17 +05301125 ieee80211_wake_queues(hw);
1126
Sujithfb9987d2010-03-17 14:25:25 +05301127 return ret;
1128}
1129
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301130static int ath9k_htc_start(struct ieee80211_hw *hw)
1131{
1132 struct ath9k_htc_priv *priv = hw->priv;
1133 int ret = 0;
1134
1135 mutex_lock(&priv->mutex);
Sujith2ff65752010-05-07 13:37:57 +05301136 ret = ath9k_htc_radio_enable(hw, false);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301137 mutex_unlock(&priv->mutex);
1138
1139 return ret;
1140}
1141
Sujith2ff65752010-05-07 13:37:57 +05301142static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led)
Sujithfb9987d2010-03-17 14:25:25 +05301143{
1144 struct ath9k_htc_priv *priv = hw->priv;
1145 struct ath_hw *ah = priv->ah;
1146 struct ath_common *common = ath9k_hw_common(ah);
1147 int ret = 0;
1148 u8 cmd_rsp;
1149
Sujithfb9987d2010-03-17 14:25:25 +05301150 if (priv->op_flags & OP_INVALID) {
1151 ath_print(common, ATH_DBG_ANY, "Device not present\n");
Sujithfb9987d2010-03-17 14:25:25 +05301152 return;
1153 }
1154
Sujith2ff65752010-05-07 13:37:57 +05301155 if (led) {
1156 /* Disable LED */
1157 ath9k_hw_set_gpio(ah, ah->led_pin, 1);
1158 ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
1159 }
1160
Sujith7073daa2010-04-23 10:28:13 +05301161 /* Cancel all the running timers/work .. */
1162 cancel_work_sync(&priv->ps_work);
1163 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1164 cancel_delayed_work_sync(&priv->ath9k_aggr_work);
1165 cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
1166 ath9k_led_stop_brightness(priv);
1167
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301168 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301169 htc_stop(priv->htc);
1170 WMI_CMD(WMI_DISABLE_INTR_CMDID);
1171 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
1172 WMI_CMD(WMI_STOP_RECV_CMDID);
1173 ath9k_hw_phy_disable(ah);
1174 ath9k_hw_disable(ah);
1175 ath9k_hw_configpcipowersave(ah, 1, 1);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301176 ath9k_htc_ps_restore(priv);
1177 ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
Sujithfb9987d2010-03-17 14:25:25 +05301178
Sujithfb9987d2010-03-17 14:25:25 +05301179 skb_queue_purge(&priv->tx_queue);
1180
1181 /* Remove monitor interface here */
1182 if (ah->opmode == NL80211_IFTYPE_MONITOR) {
1183 if (ath9k_htc_remove_monitor_interface(priv))
1184 ath_print(common, ATH_DBG_FATAL,
1185 "Unable to remove monitor interface\n");
1186 else
1187 ath_print(common, ATH_DBG_CONFIG,
1188 "Monitor interface removed\n");
1189 }
1190
1191 priv->op_flags |= OP_INVALID;
Sujithfb9987d2010-03-17 14:25:25 +05301192
1193 ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
1194}
1195
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301196static void ath9k_htc_stop(struct ieee80211_hw *hw)
1197{
1198 struct ath9k_htc_priv *priv = hw->priv;
1199
1200 mutex_lock(&priv->mutex);
Sujith2ff65752010-05-07 13:37:57 +05301201 ath9k_htc_radio_disable(hw, false);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301202 mutex_unlock(&priv->mutex);
1203}
1204
1205
Sujithfb9987d2010-03-17 14:25:25 +05301206static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
1207 struct ieee80211_vif *vif)
1208{
1209 struct ath9k_htc_priv *priv = hw->priv;
1210 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1211 struct ath_common *common = ath9k_hw_common(priv->ah);
1212 struct ath9k_htc_target_vif hvif;
1213 int ret = 0;
1214 u8 cmd_rsp;
1215
1216 mutex_lock(&priv->mutex);
1217
1218 /* Only one interface for now */
1219 if (priv->nvifs > 0) {
1220 ret = -ENOBUFS;
1221 goto out;
1222 }
1223
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301224 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301225 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1226 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1227
1228 switch (vif->type) {
1229 case NL80211_IFTYPE_STATION:
1230 hvif.opmode = cpu_to_be32(HTC_M_STA);
1231 break;
1232 case NL80211_IFTYPE_ADHOC:
1233 hvif.opmode = cpu_to_be32(HTC_M_IBSS);
1234 break;
1235 default:
1236 ath_print(common, ATH_DBG_FATAL,
1237 "Interface type %d not yet supported\n", vif->type);
1238 ret = -EOPNOTSUPP;
1239 goto out;
1240 }
1241
1242 ath_print(common, ATH_DBG_CONFIG,
1243 "Attach a VIF of type: %d\n", vif->type);
1244
1245 priv->ah->opmode = vif->type;
1246
1247 /* Index starts from zero on the target */
1248 avp->index = hvif.index = priv->nvifs;
1249 hvif.rtsthreshold = cpu_to_be16(2304);
1250 WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
1251 if (ret)
1252 goto out;
1253
1254 priv->nvifs++;
1255
1256 /*
1257 * We need a node in target to tx mgmt frames
1258 * before association.
1259 */
1260 ret = ath9k_htc_add_station(priv, vif, NULL);
1261 if (ret)
1262 goto out;
1263
1264 ret = ath9k_htc_update_cap_target(priv);
1265 if (ret)
1266 ath_print(common, ATH_DBG_CONFIG, "Failed to update"
1267 " capability in target \n");
1268
1269 priv->vif = vif;
1270out:
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301271 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301272 mutex_unlock(&priv->mutex);
1273 return ret;
1274}
1275
1276static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
1277 struct ieee80211_vif *vif)
1278{
1279 struct ath9k_htc_priv *priv = hw->priv;
1280 struct ath_common *common = ath9k_hw_common(priv->ah);
1281 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1282 struct ath9k_htc_target_vif hvif;
1283 int ret = 0;
1284 u8 cmd_rsp;
1285
1286 ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
1287
1288 mutex_lock(&priv->mutex);
1289
1290 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1291 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1292 hvif.index = avp->index;
1293 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
1294 priv->nvifs--;
1295
1296 ath9k_htc_remove_station(priv, vif, NULL);
Sujithfb9987d2010-03-17 14:25:25 +05301297 priv->vif = NULL;
1298
1299 mutex_unlock(&priv->mutex);
1300}
1301
1302static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
1303{
1304 struct ath9k_htc_priv *priv = hw->priv;
1305 struct ath_common *common = ath9k_hw_common(priv->ah);
1306 struct ieee80211_conf *conf = &hw->conf;
1307
1308 mutex_lock(&priv->mutex);
1309
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301310 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1311 bool enable_radio = false;
1312 bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
1313
1314 if (!idle && priv->ps_idle)
1315 enable_radio = true;
1316
1317 priv->ps_idle = idle;
1318
1319 if (enable_radio) {
1320 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
Sujith2ff65752010-05-07 13:37:57 +05301321 ath9k_htc_radio_enable(hw, true);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301322 ath_print(common, ATH_DBG_CONFIG,
1323 "not-idle: enabling radio\n");
1324 }
1325 }
1326
Sujithfb9987d2010-03-17 14:25:25 +05301327 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1328 struct ieee80211_channel *curchan = hw->conf.channel;
1329 int pos = curchan->hw_value;
Sujithfb9987d2010-03-17 14:25:25 +05301330
1331 ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
1332 curchan->center_freq);
1333
Sujithfb9987d2010-03-17 14:25:25 +05301334 ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
1335
1336 if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
1337 ath_print(common, ATH_DBG_FATAL,
1338 "Unable to set channel\n");
1339 mutex_unlock(&priv->mutex);
1340 return -EINVAL;
1341 }
1342
1343 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301344 if (changed & IEEE80211_CONF_CHANGE_PS) {
1345 if (conf->flags & IEEE80211_CONF_PS) {
1346 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
1347 priv->ps_enabled = true;
1348 } else {
1349 priv->ps_enabled = false;
1350 cancel_work_sync(&priv->ps_work);
1351 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1352 }
1353 }
Sujithfb9987d2010-03-17 14:25:25 +05301354
1355 if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
1356 if (conf->flags & IEEE80211_CONF_MONITOR) {
1357 if (ath9k_htc_add_monitor_interface(priv))
1358 ath_print(common, ATH_DBG_FATAL,
1359 "Failed to set monitor mode\n");
1360 else
1361 ath_print(common, ATH_DBG_CONFIG,
1362 "HW opmode set to Monitor mode\n");
1363 }
1364 }
1365
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301366 if (priv->ps_idle) {
1367 ath_print(common, ATH_DBG_CONFIG,
1368 "idle: disabling radio\n");
Sujith2ff65752010-05-07 13:37:57 +05301369 ath9k_htc_radio_disable(hw, true);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301370 }
1371
Sujithfb9987d2010-03-17 14:25:25 +05301372 mutex_unlock(&priv->mutex);
1373
1374 return 0;
1375}
1376
1377#define SUPPORTED_FILTERS \
1378 (FIF_PROMISC_IN_BSS | \
1379 FIF_ALLMULTI | \
1380 FIF_CONTROL | \
1381 FIF_PSPOLL | \
1382 FIF_OTHER_BSS | \
1383 FIF_BCN_PRBRESP_PROMISC | \
1384 FIF_FCSFAIL)
1385
1386static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
1387 unsigned int changed_flags,
1388 unsigned int *total_flags,
1389 u64 multicast)
1390{
1391 struct ath9k_htc_priv *priv = hw->priv;
1392 u32 rfilt;
1393
1394 mutex_lock(&priv->mutex);
1395
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301396 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301397 changed_flags &= SUPPORTED_FILTERS;
1398 *total_flags &= SUPPORTED_FILTERS;
1399
1400 priv->rxfilter = *total_flags;
Sujith0995d112010-03-29 16:07:09 +05301401 rfilt = ath9k_htc_calcrxfilter(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301402 ath9k_hw_setrxfilter(priv->ah, rfilt);
1403
1404 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
1405 "Set HW RX filter: 0x%x\n", rfilt);
1406
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301407 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301408 mutex_unlock(&priv->mutex);
1409}
1410
1411static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
1412 struct ieee80211_vif *vif,
1413 enum sta_notify_cmd cmd,
1414 struct ieee80211_sta *sta)
1415{
1416 struct ath9k_htc_priv *priv = hw->priv;
1417 int ret;
1418
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301419 mutex_lock(&priv->mutex);
1420
Sujithfb9987d2010-03-17 14:25:25 +05301421 switch (cmd) {
1422 case STA_NOTIFY_ADD:
1423 ret = ath9k_htc_add_station(priv, vif, sta);
1424 if (!ret)
Sujith0d425a72010-05-17 12:01:16 +05301425 ath9k_htc_init_rate(priv, sta);
Sujithfb9987d2010-03-17 14:25:25 +05301426 break;
1427 case STA_NOTIFY_REMOVE:
1428 ath9k_htc_remove_station(priv, vif, sta);
1429 break;
1430 default:
1431 break;
1432 }
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301433
1434 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301435}
1436
1437static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
1438 const struct ieee80211_tx_queue_params *params)
1439{
1440 struct ath9k_htc_priv *priv = hw->priv;
1441 struct ath_common *common = ath9k_hw_common(priv->ah);
1442 struct ath9k_tx_queue_info qi;
1443 int ret = 0, qnum;
1444
1445 if (queue >= WME_NUM_AC)
1446 return 0;
1447
1448 mutex_lock(&priv->mutex);
1449
1450 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
1451
1452 qi.tqi_aifs = params->aifs;
1453 qi.tqi_cwmin = params->cw_min;
1454 qi.tqi_cwmax = params->cw_max;
1455 qi.tqi_burstTime = params->txop;
1456
1457 qnum = get_hw_qnum(queue, priv->hwq_map);
1458
1459 ath_print(common, ATH_DBG_CONFIG,
1460 "Configure tx [queue/hwq] [%d/%d], "
1461 "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
1462 queue, qnum, params->aifs, params->cw_min,
1463 params->cw_max, params->txop);
1464
Sujithe1572c52010-03-24 13:42:13 +05301465 ret = ath_htc_txq_update(priv, qnum, &qi);
Sujithfb9987d2010-03-17 14:25:25 +05301466 if (ret)
1467 ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
1468
1469 mutex_unlock(&priv->mutex);
1470
1471 return ret;
1472}
1473
1474static int ath9k_htc_set_key(struct ieee80211_hw *hw,
1475 enum set_key_cmd cmd,
1476 struct ieee80211_vif *vif,
1477 struct ieee80211_sta *sta,
1478 struct ieee80211_key_conf *key)
1479{
1480 struct ath9k_htc_priv *priv = hw->priv;
1481 struct ath_common *common = ath9k_hw_common(priv->ah);
1482 int ret = 0;
1483
Sujithe1572c52010-03-24 13:42:13 +05301484 if (htc_modparam_nohwcrypt)
Sujithfb9987d2010-03-17 14:25:25 +05301485 return -ENOSPC;
1486
1487 mutex_lock(&priv->mutex);
1488 ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301489 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301490
1491 switch (cmd) {
1492 case SET_KEY:
1493 ret = ath9k_cmn_key_config(common, vif, sta, key);
1494 if (ret >= 0) {
1495 key->hw_key_idx = ret;
1496 /* push IV and Michael MIC generation to stack */
1497 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
1498 if (key->alg == ALG_TKIP)
1499 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
1500 if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
1501 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
1502 ret = 0;
1503 }
1504 break;
1505 case DISABLE_KEY:
1506 ath9k_cmn_key_delete(common, key);
1507 break;
1508 default:
1509 ret = -EINVAL;
1510 }
1511
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301512 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301513 mutex_unlock(&priv->mutex);
1514
1515 return ret;
1516}
1517
1518static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
1519 struct ieee80211_vif *vif,
1520 struct ieee80211_bss_conf *bss_conf,
1521 u32 changed)
1522{
1523 struct ath9k_htc_priv *priv = hw->priv;
1524 struct ath_hw *ah = priv->ah;
1525 struct ath_common *common = ath9k_hw_common(ah);
1526
1527 mutex_lock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301528 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301529
1530 if (changed & BSS_CHANGED_ASSOC) {
1531 common->curaid = bss_conf->assoc ?
1532 bss_conf->aid : 0;
1533 ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
1534 bss_conf->assoc);
1535
1536 if (bss_conf->assoc) {
1537 priv->op_flags |= OP_ASSOCIATED;
1538 ath_start_ani(priv);
1539 } else {
1540 priv->op_flags &= ~OP_ASSOCIATED;
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301541 cancel_work_sync(&priv->ps_work);
Sujithfb9987d2010-03-17 14:25:25 +05301542 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1543 }
1544 }
1545
1546 if (changed & BSS_CHANGED_BSSID) {
1547 /* Set BSSID */
1548 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1549 ath9k_hw_write_associd(ah);
1550
1551 ath_print(common, ATH_DBG_CONFIG,
1552 "BSSID: %pM aid: 0x%x\n",
1553 common->curbssid, common->curaid);
1554 }
1555
1556 if ((changed & BSS_CHANGED_BEACON_INT) ||
1557 (changed & BSS_CHANGED_BEACON) ||
1558 ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1559 bss_conf->enable_beacon)) {
1560 priv->op_flags |= OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301561 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301562 }
1563
Sujithfb9987d2010-03-17 14:25:25 +05301564 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1565 !bss_conf->enable_beacon) {
1566 priv->op_flags &= ~OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301567 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301568 }
1569
1570 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1571 ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
1572 bss_conf->use_short_preamble);
1573 if (bss_conf->use_short_preamble)
1574 priv->op_flags |= OP_PREAMBLE_SHORT;
1575 else
1576 priv->op_flags &= ~OP_PREAMBLE_SHORT;
1577 }
1578
1579 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1580 ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
1581 bss_conf->use_cts_prot);
1582 if (bss_conf->use_cts_prot &&
1583 hw->conf.channel->band != IEEE80211_BAND_5GHZ)
1584 priv->op_flags |= OP_PROTECT_ENABLE;
1585 else
1586 priv->op_flags &= ~OP_PROTECT_ENABLE;
1587 }
1588
1589 if (changed & BSS_CHANGED_ERP_SLOT) {
1590 if (bss_conf->use_short_slot)
1591 ah->slottime = 9;
1592 else
1593 ah->slottime = 20;
1594
1595 ath9k_hw_init_global_settings(ah);
1596 }
1597
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301598 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301599 mutex_unlock(&priv->mutex);
1600}
1601
1602static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
1603{
1604 struct ath9k_htc_priv *priv = hw->priv;
1605 u64 tsf;
1606
1607 mutex_lock(&priv->mutex);
1608 tsf = ath9k_hw_gettsf64(priv->ah);
1609 mutex_unlock(&priv->mutex);
1610
1611 return tsf;
1612}
1613
1614static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
1615{
1616 struct ath9k_htc_priv *priv = hw->priv;
1617
1618 mutex_lock(&priv->mutex);
1619 ath9k_hw_settsf64(priv->ah, tsf);
1620 mutex_unlock(&priv->mutex);
1621}
1622
1623static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
1624{
1625 struct ath9k_htc_priv *priv = hw->priv;
1626
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301627 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301628 mutex_lock(&priv->mutex);
1629 ath9k_hw_reset_tsf(priv->ah);
1630 mutex_unlock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301631 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301632}
1633
1634static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
1635 struct ieee80211_vif *vif,
1636 enum ieee80211_ampdu_mlme_action action,
1637 struct ieee80211_sta *sta,
1638 u16 tid, u16 *ssn)
1639{
1640 struct ath9k_htc_priv *priv = hw->priv;
1641 struct ath9k_htc_aggr_work *work = &priv->aggr_work;
1642 struct ath9k_htc_sta *ista;
1643
1644 switch (action) {
1645 case IEEE80211_AMPDU_RX_START:
1646 break;
1647 case IEEE80211_AMPDU_RX_STOP:
1648 break;
1649 case IEEE80211_AMPDU_TX_START:
1650 case IEEE80211_AMPDU_TX_STOP:
1651 if (!(priv->op_flags & OP_TXAGGR))
1652 return -ENOTSUPP;
1653 memcpy(work->sta_addr, sta->addr, ETH_ALEN);
1654 work->hw = hw;
1655 work->vif = vif;
1656 work->action = action;
1657 work->tid = tid;
1658 ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0);
1659 break;
1660 case IEEE80211_AMPDU_TX_OPERATIONAL:
1661 ista = (struct ath9k_htc_sta *) sta->drv_priv;
1662 ista->tid_state[tid] = AGGR_OPERATIONAL;
1663 break;
1664 default:
1665 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
1666 "Unknown AMPDU action\n");
1667 }
1668
1669 return 0;
1670}
1671
1672static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
1673{
1674 struct ath9k_htc_priv *priv = hw->priv;
1675
1676 mutex_lock(&priv->mutex);
1677 spin_lock_bh(&priv->beacon_lock);
1678 priv->op_flags |= OP_SCANNING;
1679 spin_unlock_bh(&priv->beacon_lock);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301680 cancel_work_sync(&priv->ps_work);
Sujithfb9987d2010-03-17 14:25:25 +05301681 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1682 mutex_unlock(&priv->mutex);
1683}
1684
1685static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
1686{
1687 struct ath9k_htc_priv *priv = hw->priv;
1688
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301689 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301690 mutex_lock(&priv->mutex);
1691 spin_lock_bh(&priv->beacon_lock);
1692 priv->op_flags &= ~OP_SCANNING;
1693 spin_unlock_bh(&priv->beacon_lock);
1694 priv->op_flags |= OP_FULL_RESET;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301695 if (priv->op_flags & OP_ASSOCIATED)
Sujithfcb93922010-04-16 11:53:48 +05301696 ath9k_htc_beacon_config(priv, priv->vif);
Sujithfb9987d2010-03-17 14:25:25 +05301697 ath_start_ani(priv);
1698 mutex_unlock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301699 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301700}
1701
1702static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1703{
1704 return 0;
1705}
1706
1707static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
1708 u8 coverage_class)
1709{
1710 struct ath9k_htc_priv *priv = hw->priv;
1711
1712 mutex_lock(&priv->mutex);
1713 priv->ah->coverage_class = coverage_class;
1714 ath9k_hw_init_global_settings(priv->ah);
1715 mutex_unlock(&priv->mutex);
1716}
1717
1718struct ieee80211_ops ath9k_htc_ops = {
1719 .tx = ath9k_htc_tx,
1720 .start = ath9k_htc_start,
1721 .stop = ath9k_htc_stop,
1722 .add_interface = ath9k_htc_add_interface,
1723 .remove_interface = ath9k_htc_remove_interface,
1724 .config = ath9k_htc_config,
1725 .configure_filter = ath9k_htc_configure_filter,
1726 .sta_notify = ath9k_htc_sta_notify,
1727 .conf_tx = ath9k_htc_conf_tx,
1728 .bss_info_changed = ath9k_htc_bss_info_changed,
1729 .set_key = ath9k_htc_set_key,
1730 .get_tsf = ath9k_htc_get_tsf,
1731 .set_tsf = ath9k_htc_set_tsf,
1732 .reset_tsf = ath9k_htc_reset_tsf,
1733 .ampdu_action = ath9k_htc_ampdu_action,
1734 .sw_scan_start = ath9k_htc_sw_scan_start,
1735 .sw_scan_complete = ath9k_htc_sw_scan_complete,
1736 .set_rts_threshold = ath9k_htc_set_rts_threshold,
1737 .rfkill_poll = ath9k_htc_rfkill_poll_state,
1738 .set_coverage_class = ath9k_htc_set_coverage_class,
1739};