blob: eb7722b2cfcca62611f0e4636a38683cc456e0ca [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
97 if (priv->ps_enabled)
98 ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP);
99unlock:
100 mutex_unlock(&priv->htc_pm_lock);
101}
102
103void ath9k_ps_work(struct work_struct *work)
104{
105 struct ath9k_htc_priv *priv =
106 container_of(work, struct ath9k_htc_priv,
107 ps_work);
108 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
109
110 /* The chip wakes up after receiving the first beacon
111 while network sleep is enabled. For the driver to
112 be in sync with the hw, set the chip to awake and
113 only then set it to sleep.
114 */
115 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
116}
117
Sujithfb9987d2010-03-17 14:25:25 +0530118static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
119 struct ieee80211_hw *hw,
120 struct ath9k_channel *hchan)
121{
122 struct ath_hw *ah = priv->ah;
123 struct ath_common *common = ath9k_hw_common(ah);
124 struct ieee80211_conf *conf = &common->hw->conf;
125 bool fastcc = true;
126 struct ieee80211_channel *channel = hw->conf.channel;
127 enum htc_phymode mode;
128 u16 htc_mode;
129 u8 cmd_rsp;
130 int ret;
131
132 if (priv->op_flags & OP_INVALID)
133 return -EIO;
134
135 if (priv->op_flags & OP_FULL_RESET)
136 fastcc = false;
137
138 /* Fiddle around with fastcc later on, for now just use full reset */
139 fastcc = false;
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530140 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530141 htc_stop(priv->htc);
142 WMI_CMD(WMI_DISABLE_INTR_CMDID);
143 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
144 WMI_CMD(WMI_STOP_RECV_CMDID);
145
146 ath_print(common, ATH_DBG_CONFIG,
147 "(%u MHz) -> (%u MHz), HT: %d, HT40: %d\n",
148 priv->ah->curchan->channel,
149 channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf));
150
151 ret = ath9k_hw_reset(ah, hchan, fastcc);
152 if (ret) {
153 ath_print(common, ATH_DBG_FATAL,
154 "Unable to reset channel (%u Mhz) "
155 "reset status %d\n", channel->center_freq, ret);
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530156 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530157 goto err;
158 }
159
160 ath_update_txpow(priv);
161
162 WMI_CMD(WMI_START_RECV_CMDID);
163 if (ret)
164 goto err;
165
166 ath9k_host_rx_init(priv);
167
168 mode = ath9k_htc_get_curmode(priv, hchan);
169 htc_mode = cpu_to_be16(mode);
170 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
171 if (ret)
172 goto err;
173
174 WMI_CMD(WMI_ENABLE_INTR_CMDID);
175 if (ret)
176 goto err;
177
178 htc_start(priv->htc);
179
180 priv->op_flags &= ~OP_FULL_RESET;
181err:
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530182 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530183 return ret;
184}
185
186static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
187{
188 struct ath_common *common = ath9k_hw_common(priv->ah);
189 struct ath9k_htc_target_vif hvif;
190 int ret = 0;
191 u8 cmd_rsp;
192
193 if (priv->nvifs > 0)
194 return -ENOBUFS;
195
196 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
197 memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
198
199 hvif.opmode = cpu_to_be32(HTC_M_MONITOR);
200 priv->ah->opmode = NL80211_IFTYPE_MONITOR;
201 hvif.index = priv->nvifs;
202
203 WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
204 if (ret)
205 return ret;
206
207 priv->nvifs++;
208 return 0;
209}
210
211static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
212{
213 struct ath_common *common = ath9k_hw_common(priv->ah);
214 struct ath9k_htc_target_vif hvif;
215 int ret = 0;
216 u8 cmd_rsp;
217
218 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
219 memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
220 hvif.index = 0; /* Should do for now */
221 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
222 priv->nvifs--;
223
224 return ret;
225}
226
227static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
228 struct ieee80211_vif *vif,
229 struct ieee80211_sta *sta)
230{
231 struct ath_common *common = ath9k_hw_common(priv->ah);
232 struct ath9k_htc_target_sta tsta;
233 struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
234 struct ath9k_htc_sta *ista;
235 int ret;
236 u8 cmd_rsp;
237
238 if (priv->nstations >= ATH9K_HTC_MAX_STA)
239 return -ENOBUFS;
240
241 memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta));
242
243 if (sta) {
244 ista = (struct ath9k_htc_sta *) sta->drv_priv;
245 memcpy(&tsta.macaddr, sta->addr, ETH_ALEN);
246 memcpy(&tsta.bssid, common->curbssid, ETH_ALEN);
247 tsta.associd = common->curaid;
248 tsta.is_vif_sta = 0;
249 tsta.valid = true;
250 ista->index = priv->nstations;
251 } else {
252 memcpy(&tsta.macaddr, vif->addr, ETH_ALEN);
253 tsta.is_vif_sta = 1;
254 }
255
256 tsta.sta_index = priv->nstations;
257 tsta.vif_index = avp->index;
258 tsta.maxampdu = 0xffff;
259 if (sta && sta->ht_cap.ht_supported)
260 tsta.flags = cpu_to_be16(ATH_HTC_STA_HT);
261
262 WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
263 if (ret) {
264 if (sta)
265 ath_print(common, ATH_DBG_FATAL,
266 "Unable to add station entry for: %pM\n", sta->addr);
267 return ret;
268 }
269
270 if (sta)
271 ath_print(common, ATH_DBG_CONFIG,
272 "Added a station entry for: %pM (idx: %d)\n",
273 sta->addr, tsta.sta_index);
274
275 priv->nstations++;
276 return 0;
277}
278
279static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
280 struct ieee80211_vif *vif,
281 struct ieee80211_sta *sta)
282{
283 struct ath_common *common = ath9k_hw_common(priv->ah);
284 struct ath9k_htc_sta *ista;
285 int ret;
286 u8 cmd_rsp, sta_idx;
287
288 if (sta) {
289 ista = (struct ath9k_htc_sta *) sta->drv_priv;
290 sta_idx = ista->index;
291 } else {
292 sta_idx = 0;
293 }
294
295 WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx);
296 if (ret) {
297 if (sta)
298 ath_print(common, ATH_DBG_FATAL,
299 "Unable to remove station entry for: %pM\n",
300 sta->addr);
301 return ret;
302 }
303
304 if (sta)
305 ath_print(common, ATH_DBG_CONFIG,
306 "Removed a station entry for: %pM (idx: %d)\n",
307 sta->addr, sta_idx);
308
309 priv->nstations--;
310 return 0;
311}
312
313static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
314{
315 struct ath9k_htc_cap_target tcap;
316 int ret;
317 u8 cmd_rsp;
318
319 memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target));
320
321 /* FIXME: Values are hardcoded */
322 tcap.flags = 0x240c40;
323 tcap.flags_ext = 0x80601000;
324 tcap.ampdu_limit = 0xffff0000;
325 tcap.ampdu_subframes = 20;
326 tcap.tx_chainmask_legacy = 1;
327 tcap.protmode = 1;
328 tcap.tx_chainmask = 1;
329
330 WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap);
331
332 return ret;
333}
334
335static int ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
336 struct ieee80211_vif *vif,
337 struct ieee80211_sta *sta)
338{
339 struct ath_common *common = ath9k_hw_common(priv->ah);
340 struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
341 struct ieee80211_supported_band *sband;
342 struct ath9k_htc_target_rate trate;
343 u32 caps = 0;
344 u8 cmd_rsp;
345 int i, j, ret;
346
347 memset(&trate, 0, sizeof(trate));
348
349 /* Only 2GHz is supported */
350 sband = priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
351
352 for (i = 0, j = 0; i < sband->n_bitrates; i++) {
353 if (sta->supp_rates[sband->band] & BIT(i)) {
354 priv->tgt_rate.rates.legacy_rates.rs_rates[j]
355 = (sband->bitrates[i].bitrate * 2) / 10;
356 j++;
357 }
358 }
359 priv->tgt_rate.rates.legacy_rates.rs_nrates = j;
360
361 if (sta->ht_cap.ht_supported) {
362 for (i = 0, j = 0; i < 77; i++) {
363 if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
364 priv->tgt_rate.rates.ht_rates.rs_rates[j++] = i;
365 if (j == ATH_HTC_RATE_MAX)
366 break;
367 }
368 priv->tgt_rate.rates.ht_rates.rs_nrates = j;
369
370 caps = WLAN_RC_HT_FLAG;
371 if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
372 caps |= WLAN_RC_40_FLAG;
373 if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
374 caps |= WLAN_RC_SGI_FLAG;
375
376 }
377
378 priv->tgt_rate.sta_index = ista->index;
379 priv->tgt_rate.isnew = 1;
380 trate = priv->tgt_rate;
381 priv->tgt_rate.capflags = caps;
382 trate.capflags = cpu_to_be32(caps);
383
384 WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
385 if (ret) {
386 ath_print(common, ATH_DBG_FATAL,
387 "Unable to initialize Rate information on target\n");
388 return ret;
389 }
390
391 ath_print(common, ATH_DBG_CONFIG,
392 "Updated target STA: %pM (caps: 0x%x)\n", sta->addr, caps);
393 return 0;
394}
395
396static bool check_rc_update(struct ieee80211_hw *hw, bool *cw40)
397{
398 struct ath9k_htc_priv *priv = hw->priv;
399 struct ieee80211_conf *conf = &hw->conf;
400
401 if (!conf_is_ht(conf))
402 return false;
403
404 if (!(priv->op_flags & OP_ASSOCIATED) ||
405 (priv->op_flags & OP_SCANNING))
406 return false;
407
408 if (conf_is_ht40(conf)) {
409 if (priv->ah->curchan->chanmode &
410 (CHANNEL_HT40PLUS | CHANNEL_HT40MINUS)) {
411 return false;
412 } else {
413 *cw40 = true;
414 return true;
415 }
416 } else { /* ht20 */
417 if (priv->ah->curchan->chanmode & CHANNEL_HT20)
418 return false;
419 else
420 return true;
421 }
422}
423
424static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40)
425{
426 struct ath9k_htc_target_rate trate;
427 struct ath_common *common = ath9k_hw_common(priv->ah);
428 int ret;
429 u8 cmd_rsp;
430
431 memset(&trate, 0, sizeof(trate));
432
433 trate = priv->tgt_rate;
434
435 if (is_cw40)
436 priv->tgt_rate.capflags |= WLAN_RC_40_FLAG;
437 else
438 priv->tgt_rate.capflags &= ~WLAN_RC_40_FLAG;
439
440 trate.capflags = cpu_to_be32(priv->tgt_rate.capflags);
441
442 WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
443 if (ret) {
444 ath_print(common, ATH_DBG_FATAL,
445 "Unable to update Rate information on target\n");
446 return;
447 }
448
449 ath_print(common, ATH_DBG_CONFIG, "Rate control updated with "
450 "caps:0x%x on target\n", priv->tgt_rate.capflags);
451}
452
453static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
454 struct ieee80211_vif *vif,
455 u8 *sta_addr, u8 tid, bool oper)
456{
457 struct ath_common *common = ath9k_hw_common(priv->ah);
458 struct ath9k_htc_target_aggr aggr;
459 struct ieee80211_sta *sta = NULL;
460 struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
461 int ret = 0;
462 u8 cmd_rsp;
463
464 if (tid > ATH9K_HTC_MAX_TID)
465 return -EINVAL;
466
Sujithfb9987d2010-03-17 14:25:25 +0530467 memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
468
Sujithef98c3c2010-03-29 16:07:11 +0530469 rcu_read_lock();
470
471 /* Check if we are able to retrieve the station */
472 sta = ieee80211_find_sta(vif, sta_addr);
473 if (!sta) {
474 rcu_read_unlock();
475 return -EINVAL;
476 }
477
478 ista = (struct ath9k_htc_sta *) sta->drv_priv;
Sujithfb9987d2010-03-17 14:25:25 +0530479
480 if (oper)
481 ista->tid_state[tid] = AGGR_START;
482 else
483 ista->tid_state[tid] = AGGR_STOP;
484
Sujithef98c3c2010-03-29 16:07:11 +0530485 aggr.sta_index = ista->index;
486
487 rcu_read_unlock();
488
489 aggr.tidno = tid;
490 aggr.aggr_enable = oper;
491
Sujithfb9987d2010-03-17 14:25:25 +0530492 WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
493 if (ret)
494 ath_print(common, ATH_DBG_CONFIG,
495 "Unable to %s TX aggregation for (%pM, %d)\n",
496 (oper) ? "start" : "stop", sta->addr, tid);
497 else
498 ath_print(common, ATH_DBG_CONFIG,
499 "%s aggregation for (%pM, %d)\n",
500 (oper) ? "Starting" : "Stopping", sta->addr, tid);
501
502 return ret;
503}
504
505void ath9k_htc_aggr_work(struct work_struct *work)
506{
507 int ret = 0;
508 struct ath9k_htc_priv *priv =
509 container_of(work, struct ath9k_htc_priv,
510 ath9k_aggr_work.work);
511 struct ath9k_htc_aggr_work *wk = &priv->aggr_work;
512
513 mutex_lock(&wk->mutex);
514
515 switch (wk->action) {
516 case IEEE80211_AMPDU_TX_START:
517 ret = ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
518 wk->tid, true);
519 if (!ret)
520 ieee80211_start_tx_ba_cb(wk->vif, wk->sta_addr,
521 wk->tid);
522 break;
523 case IEEE80211_AMPDU_TX_STOP:
524 ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
525 wk->tid, false);
526 ieee80211_stop_tx_ba_cb(wk->vif, wk->sta_addr, wk->tid);
527 break;
528 default:
529 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
530 "Unknown AMPDU action\n");
531 }
532
533 mutex_unlock(&wk->mutex);
534}
535
536/*********/
537/* DEBUG */
538/*********/
539
540#ifdef CONFIG_ATH9K_HTC_DEBUGFS
541
542static int ath9k_debugfs_open(struct inode *inode, struct file *file)
543{
544 file->private_data = inode->i_private;
545 return 0;
546}
547
548static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
549 size_t count, loff_t *ppos)
550{
551 struct ath9k_htc_priv *priv =
552 (struct ath9k_htc_priv *) file->private_data;
553 struct ath9k_htc_target_stats cmd_rsp;
554 char buf[512];
555 unsigned int len = 0;
556 int ret = 0;
557
558 memset(&cmd_rsp, 0, sizeof(cmd_rsp));
559
560 WMI_CMD(WMI_TGT_STATS_CMDID);
561 if (ret)
562 return -EINVAL;
563
564
565 len += snprintf(buf + len, sizeof(buf) - len,
566 "%19s : %10u\n", "TX Short Retries",
567 be32_to_cpu(cmd_rsp.tx_shortretry));
568 len += snprintf(buf + len, sizeof(buf) - len,
569 "%19s : %10u\n", "TX Long Retries",
570 be32_to_cpu(cmd_rsp.tx_longretry));
571 len += snprintf(buf + len, sizeof(buf) - len,
572 "%19s : %10u\n", "TX Xretries",
573 be32_to_cpu(cmd_rsp.tx_xretries));
574 len += snprintf(buf + len, sizeof(buf) - len,
575 "%19s : %10u\n", "TX Unaggr. Xretries",
576 be32_to_cpu(cmd_rsp.ht_txunaggr_xretry));
577 len += snprintf(buf + len, sizeof(buf) - len,
578 "%19s : %10u\n", "TX Xretries (HT)",
579 be32_to_cpu(cmd_rsp.ht_tx_xretries));
580 len += snprintf(buf + len, sizeof(buf) - len,
581 "%19s : %10u\n", "TX Rate", priv->debug.txrate);
582
583 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
584}
585
586static const struct file_operations fops_tgt_stats = {
587 .read = read_file_tgt_stats,
588 .open = ath9k_debugfs_open,
589 .owner = THIS_MODULE
590};
591
592static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
593 size_t count, loff_t *ppos)
594{
595 struct ath9k_htc_priv *priv =
596 (struct ath9k_htc_priv *) file->private_data;
597 char buf[512];
598 unsigned int len = 0;
599
600 len += snprintf(buf + len, sizeof(buf) - len,
601 "%20s : %10u\n", "Buffers queued",
602 priv->debug.tx_stats.buf_queued);
603 len += snprintf(buf + len, sizeof(buf) - len,
604 "%20s : %10u\n", "Buffers completed",
605 priv->debug.tx_stats.buf_completed);
606 len += snprintf(buf + len, sizeof(buf) - len,
607 "%20s : %10u\n", "SKBs queued",
608 priv->debug.tx_stats.skb_queued);
609 len += snprintf(buf + len, sizeof(buf) - len,
610 "%20s : %10u\n", "SKBs completed",
611 priv->debug.tx_stats.skb_completed);
612
613 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
614}
615
616static const struct file_operations fops_xmit = {
617 .read = read_file_xmit,
618 .open = ath9k_debugfs_open,
619 .owner = THIS_MODULE
620};
621
622static ssize_t read_file_recv(struct file *file, char __user *user_buf,
623 size_t count, loff_t *ppos)
624{
625 struct ath9k_htc_priv *priv =
626 (struct ath9k_htc_priv *) file->private_data;
627 char buf[512];
628 unsigned int len = 0;
629
630 len += snprintf(buf + len, sizeof(buf) - len,
631 "%20s : %10u\n", "SKBs allocated",
632 priv->debug.rx_stats.skb_allocated);
633 len += snprintf(buf + len, sizeof(buf) - len,
634 "%20s : %10u\n", "SKBs completed",
635 priv->debug.rx_stats.skb_completed);
636 len += snprintf(buf + len, sizeof(buf) - len,
637 "%20s : %10u\n", "SKBs Dropped",
638 priv->debug.rx_stats.skb_dropped);
639
640 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
641}
642
643static const struct file_operations fops_recv = {
644 .read = read_file_recv,
645 .open = ath9k_debugfs_open,
646 .owner = THIS_MODULE
647};
648
Sujithe1572c52010-03-24 13:42:13 +0530649int ath9k_htc_init_debug(struct ath_hw *ah)
Sujithfb9987d2010-03-17 14:25:25 +0530650{
651 struct ath_common *common = ath9k_hw_common(ah);
652 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
653
654 if (!ath9k_debugfs_root)
655 return -ENOENT;
656
657 priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy),
658 ath9k_debugfs_root);
659 if (!priv->debug.debugfs_phy)
660 goto err;
661
662 priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR,
663 priv->debug.debugfs_phy,
664 priv, &fops_tgt_stats);
665 if (!priv->debug.debugfs_tgt_stats)
666 goto err;
667
668
669 priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR,
670 priv->debug.debugfs_phy,
671 priv, &fops_xmit);
672 if (!priv->debug.debugfs_xmit)
673 goto err;
674
675 priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR,
676 priv->debug.debugfs_phy,
677 priv, &fops_recv);
678 if (!priv->debug.debugfs_recv)
679 goto err;
680
681 return 0;
682
683err:
Sujithe1572c52010-03-24 13:42:13 +0530684 ath9k_htc_exit_debug(ah);
Sujithfb9987d2010-03-17 14:25:25 +0530685 return -ENOMEM;
686}
687
Sujithe1572c52010-03-24 13:42:13 +0530688void ath9k_htc_exit_debug(struct ath_hw *ah)
Sujithfb9987d2010-03-17 14:25:25 +0530689{
690 struct ath_common *common = ath9k_hw_common(ah);
691 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
692
693 debugfs_remove(priv->debug.debugfs_recv);
694 debugfs_remove(priv->debug.debugfs_xmit);
695 debugfs_remove(priv->debug.debugfs_tgt_stats);
696 debugfs_remove(priv->debug.debugfs_phy);
697}
698
Sujithe1572c52010-03-24 13:42:13 +0530699int ath9k_htc_debug_create_root(void)
Sujithfb9987d2010-03-17 14:25:25 +0530700{
701 ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
702 if (!ath9k_debugfs_root)
703 return -ENOENT;
704
705 return 0;
706}
707
Sujithe1572c52010-03-24 13:42:13 +0530708void ath9k_htc_debug_remove_root(void)
Sujithfb9987d2010-03-17 14:25:25 +0530709{
710 debugfs_remove(ath9k_debugfs_root);
711 ath9k_debugfs_root = NULL;
712}
713
714#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
715
716/*******/
717/* ANI */
718/*******/
719
720static void ath_start_ani(struct ath9k_htc_priv *priv)
721{
722 struct ath_common *common = ath9k_hw_common(priv->ah);
723 unsigned long timestamp = jiffies_to_msecs(jiffies);
724
725 common->ani.longcal_timer = timestamp;
726 common->ani.shortcal_timer = timestamp;
727 common->ani.checkani_timer = timestamp;
728
729 ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
730 msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
731}
732
733void ath9k_ani_work(struct work_struct *work)
734{
735 struct ath9k_htc_priv *priv =
736 container_of(work, struct ath9k_htc_priv,
737 ath9k_ani_work.work);
738 struct ath_hw *ah = priv->ah;
739 struct ath_common *common = ath9k_hw_common(ah);
740 bool longcal = false;
741 bool shortcal = false;
742 bool aniflag = false;
743 unsigned int timestamp = jiffies_to_msecs(jiffies);
744 u32 cal_interval, short_cal_interval;
745
746 short_cal_interval = ATH_STA_SHORT_CALINTERVAL;
747
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530748 /* Only calibrate if awake */
749 if (ah->power_mode != ATH9K_PM_AWAKE)
750 goto set_timer;
751
Sujithfb9987d2010-03-17 14:25:25 +0530752 /* Long calibration runs independently of short calibration. */
753 if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
754 longcal = true;
755 ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
756 common->ani.longcal_timer = timestamp;
757 }
758
759 /* Short calibration applies only while caldone is false */
760 if (!common->ani.caldone) {
761 if ((timestamp - common->ani.shortcal_timer) >=
762 short_cal_interval) {
763 shortcal = true;
764 ath_print(common, ATH_DBG_ANI,
765 "shortcal @%lu\n", jiffies);
766 common->ani.shortcal_timer = timestamp;
767 common->ani.resetcal_timer = timestamp;
768 }
769 } else {
770 if ((timestamp - common->ani.resetcal_timer) >=
771 ATH_RESTART_CALINTERVAL) {
772 common->ani.caldone = ath9k_hw_reset_calvalid(ah);
773 if (common->ani.caldone)
774 common->ani.resetcal_timer = timestamp;
775 }
776 }
777
778 /* Verify whether we must check ANI */
779 if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
780 aniflag = true;
781 common->ani.checkani_timer = timestamp;
782 }
783
784 /* Skip all processing if there's nothing to do. */
785 if (longcal || shortcal || aniflag) {
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530786
787 ath9k_htc_ps_wakeup(priv);
788
Sujithfb9987d2010-03-17 14:25:25 +0530789 /* Call ANI routine if necessary */
790 if (aniflag)
791 ath9k_hw_ani_monitor(ah, ah->curchan);
792
793 /* Perform calibration if necessary */
794 if (longcal || shortcal) {
795 common->ani.caldone =
796 ath9k_hw_calibrate(ah, ah->curchan,
797 common->rx_chainmask,
798 longcal);
799
800 if (longcal)
801 common->ani.noise_floor =
802 ath9k_hw_getchan_noise(ah, ah->curchan);
803
804 ath_print(common, ATH_DBG_ANI,
805 " calibrate chan %u/%x nf: %d\n",
806 ah->curchan->channel,
807 ah->curchan->channelFlags,
808 common->ani.noise_floor);
809 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530810
811 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530812 }
813
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530814set_timer:
Sujithfb9987d2010-03-17 14:25:25 +0530815 /*
816 * Set timer interval based on previous results.
817 * The interval must be the shortest necessary to satisfy ANI,
818 * short calibration and long calibration.
819 */
820 cal_interval = ATH_LONG_CALINTERVAL;
821 if (priv->ah->config.enable_ani)
822 cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
823 if (!common->ani.caldone)
824 cal_interval = min(cal_interval, (u32)short_cal_interval);
825
826 ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
827 msecs_to_jiffies(cal_interval));
828}
829
830/*******/
831/* LED */
832/*******/
833
834static void ath9k_led_blink_work(struct work_struct *work)
835{
836 struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
837 ath9k_led_blink_work.work);
838
839 if (!(priv->op_flags & OP_LED_ASSOCIATED))
840 return;
841
842 if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
843 (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
844 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
845 else
846 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
847 (priv->op_flags & OP_LED_ON) ? 1 : 0);
848
849 ieee80211_queue_delayed_work(priv->hw,
850 &priv->ath9k_led_blink_work,
851 (priv->op_flags & OP_LED_ON) ?
852 msecs_to_jiffies(priv->led_off_duration) :
853 msecs_to_jiffies(priv->led_on_duration));
854
855 priv->led_on_duration = priv->led_on_cnt ?
856 max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
857 ATH_LED_ON_DURATION_IDLE;
858 priv->led_off_duration = priv->led_off_cnt ?
859 max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
860 ATH_LED_OFF_DURATION_IDLE;
861 priv->led_on_cnt = priv->led_off_cnt = 0;
862
863 if (priv->op_flags & OP_LED_ON)
864 priv->op_flags &= ~OP_LED_ON;
865 else
866 priv->op_flags |= OP_LED_ON;
867}
868
869static void ath9k_led_brightness_work(struct work_struct *work)
870{
871 struct ath_led *led = container_of(work, struct ath_led,
872 brightness_work.work);
873 struct ath9k_htc_priv *priv = led->priv;
874
875 switch (led->brightness) {
876 case LED_OFF:
877 if (led->led_type == ATH_LED_ASSOC ||
878 led->led_type == ATH_LED_RADIO) {
879 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
880 (led->led_type == ATH_LED_RADIO));
881 priv->op_flags &= ~OP_LED_ASSOCIATED;
882 if (led->led_type == ATH_LED_RADIO)
883 priv->op_flags &= ~OP_LED_ON;
884 } else {
885 priv->led_off_cnt++;
886 }
887 break;
888 case LED_FULL:
889 if (led->led_type == ATH_LED_ASSOC) {
890 priv->op_flags |= OP_LED_ASSOCIATED;
891 ieee80211_queue_delayed_work(priv->hw,
892 &priv->ath9k_led_blink_work, 0);
893 } else if (led->led_type == ATH_LED_RADIO) {
894 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
895 priv->op_flags |= OP_LED_ON;
896 } else {
897 priv->led_on_cnt++;
898 }
899 break;
900 default:
901 break;
902 }
903}
904
905static void ath9k_led_brightness(struct led_classdev *led_cdev,
906 enum led_brightness brightness)
907{
908 struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
909 struct ath9k_htc_priv *priv = led->priv;
910
911 led->brightness = brightness;
912 if (!(priv->op_flags & OP_LED_DEINIT))
913 ieee80211_queue_delayed_work(priv->hw,
914 &led->brightness_work, 0);
915}
916
917static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
918{
919 cancel_delayed_work_sync(&priv->radio_led.brightness_work);
920 cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
921 cancel_delayed_work_sync(&priv->tx_led.brightness_work);
922 cancel_delayed_work_sync(&priv->rx_led.brightness_work);
923}
924
925static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
926 char *trigger)
927{
928 int ret;
929
930 led->priv = priv;
931 led->led_cdev.name = led->name;
932 led->led_cdev.default_trigger = trigger;
933 led->led_cdev.brightness_set = ath9k_led_brightness;
934
935 ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
936 if (ret)
937 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
938 "Failed to register led:%s", led->name);
939 else
940 led->registered = 1;
941
942 INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
943
944 return ret;
945}
946
947static void ath9k_unregister_led(struct ath_led *led)
948{
949 if (led->registered) {
950 led_classdev_unregister(&led->led_cdev);
951 led->registered = 0;
952 }
953}
954
955void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
956{
957 priv->op_flags |= OP_LED_DEINIT;
958 ath9k_unregister_led(&priv->assoc_led);
959 priv->op_flags &= ~OP_LED_ASSOCIATED;
960 ath9k_unregister_led(&priv->tx_led);
961 ath9k_unregister_led(&priv->rx_led);
962 ath9k_unregister_led(&priv->radio_led);
963 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
964}
965
966void ath9k_init_leds(struct ath9k_htc_priv *priv)
967{
968 char *trigger;
969 int ret;
970
971 if (AR_SREV_9287(priv->ah))
972 priv->ah->led_pin = ATH_LED_PIN_9287;
973 else if (AR_SREV_9271(priv->ah))
974 priv->ah->led_pin = ATH_LED_PIN_9271;
975 else
976 priv->ah->led_pin = ATH_LED_PIN_DEF;
977
978 /* Configure gpio 1 for output */
979 ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
980 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
981 /* LED off, active low */
982 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
983
984 INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
985
986 trigger = ieee80211_get_radio_led_name(priv->hw);
987 snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
988 "ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
989 ret = ath9k_register_led(priv, &priv->radio_led, trigger);
990 priv->radio_led.led_type = ATH_LED_RADIO;
991 if (ret)
992 goto fail;
993
994 trigger = ieee80211_get_assoc_led_name(priv->hw);
995 snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
996 "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
997 ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
998 priv->assoc_led.led_type = ATH_LED_ASSOC;
999 if (ret)
1000 goto fail;
1001
1002 trigger = ieee80211_get_tx_led_name(priv->hw);
1003 snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
1004 "ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
1005 ret = ath9k_register_led(priv, &priv->tx_led, trigger);
1006 priv->tx_led.led_type = ATH_LED_TX;
1007 if (ret)
1008 goto fail;
1009
1010 trigger = ieee80211_get_rx_led_name(priv->hw);
1011 snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
1012 "ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
1013 ret = ath9k_register_led(priv, &priv->rx_led, trigger);
1014 priv->rx_led.led_type = ATH_LED_RX;
1015 if (ret)
1016 goto fail;
1017
1018 priv->op_flags &= ~OP_LED_DEINIT;
1019
1020 return;
1021
1022fail:
1023 cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
1024 ath9k_deinit_leds(priv);
1025}
1026
1027/*******************/
1028/* Rfkill */
1029/*******************/
1030
1031static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
1032{
1033 return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
1034 priv->ah->rfkill_polarity;
1035}
1036
1037static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
1038{
1039 struct ath9k_htc_priv *priv = hw->priv;
1040 bool blocked = !!ath_is_rfkill_set(priv);
1041
1042 wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
1043}
1044
1045void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
1046{
1047 if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
1048 wiphy_rfkill_start_polling(priv->hw->wiphy);
1049}
1050
1051/**********************/
1052/* mac80211 Callbacks */
1053/**********************/
1054
1055static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1056{
1057 struct ieee80211_hdr *hdr;
1058 struct ath9k_htc_priv *priv = hw->priv;
Sujith7757dfe2010-03-29 16:07:17 +05301059 int padpos, padsize, ret;
Sujithfb9987d2010-03-17 14:25:25 +05301060
1061 hdr = (struct ieee80211_hdr *) skb->data;
1062
1063 /* Add the padding after the header if this is not already done */
1064 padpos = ath9k_cmn_padpos(hdr->frame_control);
1065 padsize = padpos & 3;
1066 if (padsize && skb->len > padpos) {
1067 if (skb_headroom(skb) < padsize)
1068 return -1;
1069 skb_push(skb, padsize);
1070 memmove(skb->data, skb->data + padsize, padpos);
1071 }
1072
Sujith7757dfe2010-03-29 16:07:17 +05301073 ret = ath9k_htc_tx_start(priv, skb);
1074 if (ret != 0) {
1075 if (ret == -ENOMEM) {
1076 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1077 "Stopping TX queues\n");
1078 ieee80211_stop_queues(hw);
1079 spin_lock_bh(&priv->tx_lock);
1080 priv->tx_queues_stop = true;
1081 spin_unlock_bh(&priv->tx_lock);
1082 } else {
1083 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1084 "Tx failed");
1085 }
Sujithfb9987d2010-03-17 14:25:25 +05301086 goto fail_tx;
1087 }
1088
1089 return 0;
1090
1091fail_tx:
1092 dev_kfree_skb_any(skb);
1093 return 0;
1094}
1095
1096static int ath9k_htc_start(struct ieee80211_hw *hw)
1097{
1098 struct ath9k_htc_priv *priv = hw->priv;
1099 struct ath_hw *ah = priv->ah;
1100 struct ath_common *common = ath9k_hw_common(ah);
1101 struct ieee80211_channel *curchan = hw->conf.channel;
1102 struct ath9k_channel *init_channel;
1103 int ret = 0;
1104 enum htc_phymode mode;
1105 u16 htc_mode;
1106 u8 cmd_rsp;
1107
1108 ath_print(common, ATH_DBG_CONFIG,
1109 "Starting driver with initial channel: %d MHz\n",
1110 curchan->center_freq);
1111
1112 mutex_lock(&priv->mutex);
1113
1114 /* setup initial channel */
1115 init_channel = ath9k_cmn_get_curchannel(hw, ah);
1116
1117 /* Reset SERDES registers */
1118 ath9k_hw_configpcipowersave(ah, 0, 0);
1119
1120 ath9k_hw_htc_resetinit(ah);
1121 ret = ath9k_hw_reset(ah, init_channel, false);
1122 if (ret) {
1123 ath_print(common, ATH_DBG_FATAL,
1124 "Unable to reset hardware; reset status %d "
1125 "(freq %u MHz)\n", ret, curchan->center_freq);
1126 goto mutex_unlock;
1127 }
1128
1129 ath_update_txpow(priv);
1130
1131 mode = ath9k_htc_get_curmode(priv, init_channel);
1132 htc_mode = cpu_to_be16(mode);
1133 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
1134 if (ret)
1135 goto mutex_unlock;
1136
1137 WMI_CMD(WMI_ATH_INIT_CMDID);
1138 if (ret)
1139 goto mutex_unlock;
1140
1141 WMI_CMD(WMI_START_RECV_CMDID);
1142 if (ret)
1143 goto mutex_unlock;
1144
1145 ath9k_host_rx_init(priv);
1146
1147 priv->op_flags &= ~OP_INVALID;
1148 htc_start(priv->htc);
1149
Sujith7757dfe2010-03-29 16:07:17 +05301150 spin_lock_bh(&priv->tx_lock);
1151 priv->tx_queues_stop = false;
1152 spin_unlock_bh(&priv->tx_lock);
1153
1154 ieee80211_wake_queues(hw);
1155
Sujithfb9987d2010-03-17 14:25:25 +05301156mutex_unlock:
1157 mutex_unlock(&priv->mutex);
1158 return ret;
1159}
1160
1161static void ath9k_htc_stop(struct ieee80211_hw *hw)
1162{
1163 struct ath9k_htc_priv *priv = hw->priv;
1164 struct ath_hw *ah = priv->ah;
1165 struct ath_common *common = ath9k_hw_common(ah);
1166 int ret = 0;
1167 u8 cmd_rsp;
1168
1169 mutex_lock(&priv->mutex);
1170
1171 if (priv->op_flags & OP_INVALID) {
1172 ath_print(common, ATH_DBG_ANY, "Device not present\n");
1173 mutex_unlock(&priv->mutex);
1174 return;
1175 }
1176
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301177 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301178 htc_stop(priv->htc);
1179 WMI_CMD(WMI_DISABLE_INTR_CMDID);
1180 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
1181 WMI_CMD(WMI_STOP_RECV_CMDID);
1182 ath9k_hw_phy_disable(ah);
1183 ath9k_hw_disable(ah);
1184 ath9k_hw_configpcipowersave(ah, 1, 1);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301185 ath9k_htc_ps_restore(priv);
1186 ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
Sujithfb9987d2010-03-17 14:25:25 +05301187
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301188 cancel_work_sync(&priv->ps_work);
Sujithfb9987d2010-03-17 14:25:25 +05301189 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1190 cancel_delayed_work_sync(&priv->ath9k_aggr_work);
1191 cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
1192 ath9k_led_stop_brightness(priv);
1193 skb_queue_purge(&priv->tx_queue);
1194
1195 /* Remove monitor interface here */
1196 if (ah->opmode == NL80211_IFTYPE_MONITOR) {
1197 if (ath9k_htc_remove_monitor_interface(priv))
1198 ath_print(common, ATH_DBG_FATAL,
1199 "Unable to remove monitor interface\n");
1200 else
1201 ath_print(common, ATH_DBG_CONFIG,
1202 "Monitor interface removed\n");
1203 }
1204
1205 priv->op_flags |= OP_INVALID;
1206 mutex_unlock(&priv->mutex);
1207
1208 ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
1209}
1210
1211static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
1212 struct ieee80211_vif *vif)
1213{
1214 struct ath9k_htc_priv *priv = hw->priv;
1215 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1216 struct ath_common *common = ath9k_hw_common(priv->ah);
1217 struct ath9k_htc_target_vif hvif;
1218 int ret = 0;
1219 u8 cmd_rsp;
1220
1221 mutex_lock(&priv->mutex);
1222
1223 /* Only one interface for now */
1224 if (priv->nvifs > 0) {
1225 ret = -ENOBUFS;
1226 goto out;
1227 }
1228
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301229 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301230 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1231 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1232
1233 switch (vif->type) {
1234 case NL80211_IFTYPE_STATION:
1235 hvif.opmode = cpu_to_be32(HTC_M_STA);
1236 break;
1237 case NL80211_IFTYPE_ADHOC:
1238 hvif.opmode = cpu_to_be32(HTC_M_IBSS);
1239 break;
1240 default:
1241 ath_print(common, ATH_DBG_FATAL,
1242 "Interface type %d not yet supported\n", vif->type);
1243 ret = -EOPNOTSUPP;
1244 goto out;
1245 }
1246
1247 ath_print(common, ATH_DBG_CONFIG,
1248 "Attach a VIF of type: %d\n", vif->type);
1249
1250 priv->ah->opmode = vif->type;
1251
1252 /* Index starts from zero on the target */
1253 avp->index = hvif.index = priv->nvifs;
1254 hvif.rtsthreshold = cpu_to_be16(2304);
1255 WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
1256 if (ret)
1257 goto out;
1258
1259 priv->nvifs++;
1260
1261 /*
1262 * We need a node in target to tx mgmt frames
1263 * before association.
1264 */
1265 ret = ath9k_htc_add_station(priv, vif, NULL);
1266 if (ret)
1267 goto out;
1268
1269 ret = ath9k_htc_update_cap_target(priv);
1270 if (ret)
1271 ath_print(common, ATH_DBG_CONFIG, "Failed to update"
1272 " capability in target \n");
1273
1274 priv->vif = vif;
1275out:
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301276 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301277 mutex_unlock(&priv->mutex);
1278 return ret;
1279}
1280
1281static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
1282 struct ieee80211_vif *vif)
1283{
1284 struct ath9k_htc_priv *priv = hw->priv;
1285 struct ath_common *common = ath9k_hw_common(priv->ah);
1286 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1287 struct ath9k_htc_target_vif hvif;
1288 int ret = 0;
1289 u8 cmd_rsp;
1290
1291 ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
1292
1293 mutex_lock(&priv->mutex);
1294
1295 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1296 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1297 hvif.index = avp->index;
1298 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
1299 priv->nvifs--;
1300
1301 ath9k_htc_remove_station(priv, vif, NULL);
1302
1303 if (vif->type == NL80211_IFTYPE_ADHOC) {
1304 spin_lock_bh(&priv->beacon_lock);
1305 if (priv->beacon)
1306 dev_kfree_skb_any(priv->beacon);
1307 priv->beacon = NULL;
1308 spin_unlock_bh(&priv->beacon_lock);
1309 }
1310
1311 priv->vif = NULL;
1312
1313 mutex_unlock(&priv->mutex);
1314}
1315
1316static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
1317{
1318 struct ath9k_htc_priv *priv = hw->priv;
1319 struct ath_common *common = ath9k_hw_common(priv->ah);
1320 struct ieee80211_conf *conf = &hw->conf;
1321
1322 mutex_lock(&priv->mutex);
1323
1324 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1325 struct ieee80211_channel *curchan = hw->conf.channel;
1326 int pos = curchan->hw_value;
1327 bool is_cw40 = false;
1328
1329 ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
1330 curchan->center_freq);
1331
1332 if (check_rc_update(hw, &is_cw40))
1333 ath9k_htc_rc_update(priv, is_cw40);
1334
1335 ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
1336
1337 if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
1338 ath_print(common, ATH_DBG_FATAL,
1339 "Unable to set channel\n");
1340 mutex_unlock(&priv->mutex);
1341 return -EINVAL;
1342 }
1343
1344 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301345 if (changed & IEEE80211_CONF_CHANGE_PS) {
1346 if (conf->flags & IEEE80211_CONF_PS) {
1347 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
1348 priv->ps_enabled = true;
1349 } else {
1350 priv->ps_enabled = false;
1351 cancel_work_sync(&priv->ps_work);
1352 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1353 }
1354 }
Sujithfb9987d2010-03-17 14:25:25 +05301355
1356 if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
1357 if (conf->flags & IEEE80211_CONF_MONITOR) {
1358 if (ath9k_htc_add_monitor_interface(priv))
1359 ath_print(common, ATH_DBG_FATAL,
1360 "Failed to set monitor mode\n");
1361 else
1362 ath_print(common, ATH_DBG_CONFIG,
1363 "HW opmode set to Monitor mode\n");
1364 }
1365 }
1366
1367 mutex_unlock(&priv->mutex);
1368
1369 return 0;
1370}
1371
1372#define SUPPORTED_FILTERS \
1373 (FIF_PROMISC_IN_BSS | \
1374 FIF_ALLMULTI | \
1375 FIF_CONTROL | \
1376 FIF_PSPOLL | \
1377 FIF_OTHER_BSS | \
1378 FIF_BCN_PRBRESP_PROMISC | \
1379 FIF_FCSFAIL)
1380
1381static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
1382 unsigned int changed_flags,
1383 unsigned int *total_flags,
1384 u64 multicast)
1385{
1386 struct ath9k_htc_priv *priv = hw->priv;
1387 u32 rfilt;
1388
1389 mutex_lock(&priv->mutex);
1390
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301391 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301392 changed_flags &= SUPPORTED_FILTERS;
1393 *total_flags &= SUPPORTED_FILTERS;
1394
1395 priv->rxfilter = *total_flags;
Sujith0995d112010-03-29 16:07:09 +05301396 rfilt = ath9k_htc_calcrxfilter(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301397 ath9k_hw_setrxfilter(priv->ah, rfilt);
1398
1399 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
1400 "Set HW RX filter: 0x%x\n", rfilt);
1401
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301402 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301403 mutex_unlock(&priv->mutex);
1404}
1405
1406static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
1407 struct ieee80211_vif *vif,
1408 enum sta_notify_cmd cmd,
1409 struct ieee80211_sta *sta)
1410{
1411 struct ath9k_htc_priv *priv = hw->priv;
1412 int ret;
1413
1414 switch (cmd) {
1415 case STA_NOTIFY_ADD:
1416 ret = ath9k_htc_add_station(priv, vif, sta);
1417 if (!ret)
1418 ath9k_htc_init_rate(priv, vif, sta);
1419 break;
1420 case STA_NOTIFY_REMOVE:
1421 ath9k_htc_remove_station(priv, vif, sta);
1422 break;
1423 default:
1424 break;
1425 }
1426}
1427
1428static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
1429 const struct ieee80211_tx_queue_params *params)
1430{
1431 struct ath9k_htc_priv *priv = hw->priv;
1432 struct ath_common *common = ath9k_hw_common(priv->ah);
1433 struct ath9k_tx_queue_info qi;
1434 int ret = 0, qnum;
1435
1436 if (queue >= WME_NUM_AC)
1437 return 0;
1438
1439 mutex_lock(&priv->mutex);
1440
1441 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
1442
1443 qi.tqi_aifs = params->aifs;
1444 qi.tqi_cwmin = params->cw_min;
1445 qi.tqi_cwmax = params->cw_max;
1446 qi.tqi_burstTime = params->txop;
1447
1448 qnum = get_hw_qnum(queue, priv->hwq_map);
1449
1450 ath_print(common, ATH_DBG_CONFIG,
1451 "Configure tx [queue/hwq] [%d/%d], "
1452 "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
1453 queue, qnum, params->aifs, params->cw_min,
1454 params->cw_max, params->txop);
1455
Sujithe1572c52010-03-24 13:42:13 +05301456 ret = ath_htc_txq_update(priv, qnum, &qi);
Sujithfb9987d2010-03-17 14:25:25 +05301457 if (ret)
1458 ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
1459
1460 mutex_unlock(&priv->mutex);
1461
1462 return ret;
1463}
1464
1465static int ath9k_htc_set_key(struct ieee80211_hw *hw,
1466 enum set_key_cmd cmd,
1467 struct ieee80211_vif *vif,
1468 struct ieee80211_sta *sta,
1469 struct ieee80211_key_conf *key)
1470{
1471 struct ath9k_htc_priv *priv = hw->priv;
1472 struct ath_common *common = ath9k_hw_common(priv->ah);
1473 int ret = 0;
1474
Sujithe1572c52010-03-24 13:42:13 +05301475 if (htc_modparam_nohwcrypt)
Sujithfb9987d2010-03-17 14:25:25 +05301476 return -ENOSPC;
1477
1478 mutex_lock(&priv->mutex);
1479 ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301480 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301481
1482 switch (cmd) {
1483 case SET_KEY:
1484 ret = ath9k_cmn_key_config(common, vif, sta, key);
1485 if (ret >= 0) {
1486 key->hw_key_idx = ret;
1487 /* push IV and Michael MIC generation to stack */
1488 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
1489 if (key->alg == ALG_TKIP)
1490 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
1491 if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
1492 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
1493 ret = 0;
1494 }
1495 break;
1496 case DISABLE_KEY:
1497 ath9k_cmn_key_delete(common, key);
1498 break;
1499 default:
1500 ret = -EINVAL;
1501 }
1502
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301503 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301504 mutex_unlock(&priv->mutex);
1505
1506 return ret;
1507}
1508
1509static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
1510 struct ieee80211_vif *vif,
1511 struct ieee80211_bss_conf *bss_conf,
1512 u32 changed)
1513{
1514 struct ath9k_htc_priv *priv = hw->priv;
1515 struct ath_hw *ah = priv->ah;
1516 struct ath_common *common = ath9k_hw_common(ah);
1517
1518 mutex_lock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301519 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301520
1521 if (changed & BSS_CHANGED_ASSOC) {
1522 common->curaid = bss_conf->assoc ?
1523 bss_conf->aid : 0;
1524 ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
1525 bss_conf->assoc);
1526
1527 if (bss_conf->assoc) {
1528 priv->op_flags |= OP_ASSOCIATED;
1529 ath_start_ani(priv);
1530 } else {
1531 priv->op_flags &= ~OP_ASSOCIATED;
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301532 cancel_work_sync(&priv->ps_work);
Sujithfb9987d2010-03-17 14:25:25 +05301533 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1534 }
1535 }
1536
1537 if (changed & BSS_CHANGED_BSSID) {
1538 /* Set BSSID */
1539 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1540 ath9k_hw_write_associd(ah);
1541
1542 ath_print(common, ATH_DBG_CONFIG,
1543 "BSSID: %pM aid: 0x%x\n",
1544 common->curbssid, common->curaid);
1545 }
1546
1547 if ((changed & BSS_CHANGED_BEACON_INT) ||
1548 (changed & BSS_CHANGED_BEACON) ||
1549 ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1550 bss_conf->enable_beacon)) {
1551 priv->op_flags |= OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301552 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301553 }
1554
1555 if (changed & BSS_CHANGED_BEACON)
1556 ath9k_htc_beacon_update(priv, vif);
1557
1558 if ((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
1564 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1565 ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
1566 bss_conf->use_short_preamble);
1567 if (bss_conf->use_short_preamble)
1568 priv->op_flags |= OP_PREAMBLE_SHORT;
1569 else
1570 priv->op_flags &= ~OP_PREAMBLE_SHORT;
1571 }
1572
1573 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1574 ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
1575 bss_conf->use_cts_prot);
1576 if (bss_conf->use_cts_prot &&
1577 hw->conf.channel->band != IEEE80211_BAND_5GHZ)
1578 priv->op_flags |= OP_PROTECT_ENABLE;
1579 else
1580 priv->op_flags &= ~OP_PROTECT_ENABLE;
1581 }
1582
1583 if (changed & BSS_CHANGED_ERP_SLOT) {
1584 if (bss_conf->use_short_slot)
1585 ah->slottime = 9;
1586 else
1587 ah->slottime = 20;
1588
1589 ath9k_hw_init_global_settings(ah);
1590 }
1591
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301592 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301593 mutex_unlock(&priv->mutex);
1594}
1595
1596static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
1597{
1598 struct ath9k_htc_priv *priv = hw->priv;
1599 u64 tsf;
1600
1601 mutex_lock(&priv->mutex);
1602 tsf = ath9k_hw_gettsf64(priv->ah);
1603 mutex_unlock(&priv->mutex);
1604
1605 return tsf;
1606}
1607
1608static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
1609{
1610 struct ath9k_htc_priv *priv = hw->priv;
1611
1612 mutex_lock(&priv->mutex);
1613 ath9k_hw_settsf64(priv->ah, tsf);
1614 mutex_unlock(&priv->mutex);
1615}
1616
1617static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
1618{
1619 struct ath9k_htc_priv *priv = hw->priv;
1620
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301621 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301622 mutex_lock(&priv->mutex);
1623 ath9k_hw_reset_tsf(priv->ah);
1624 mutex_unlock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301625 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301626}
1627
1628static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
1629 struct ieee80211_vif *vif,
1630 enum ieee80211_ampdu_mlme_action action,
1631 struct ieee80211_sta *sta,
1632 u16 tid, u16 *ssn)
1633{
1634 struct ath9k_htc_priv *priv = hw->priv;
1635 struct ath9k_htc_aggr_work *work = &priv->aggr_work;
1636 struct ath9k_htc_sta *ista;
1637
1638 switch (action) {
1639 case IEEE80211_AMPDU_RX_START:
1640 break;
1641 case IEEE80211_AMPDU_RX_STOP:
1642 break;
1643 case IEEE80211_AMPDU_TX_START:
1644 case IEEE80211_AMPDU_TX_STOP:
1645 if (!(priv->op_flags & OP_TXAGGR))
1646 return -ENOTSUPP;
1647 memcpy(work->sta_addr, sta->addr, ETH_ALEN);
1648 work->hw = hw;
1649 work->vif = vif;
1650 work->action = action;
1651 work->tid = tid;
1652 ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0);
1653 break;
1654 case IEEE80211_AMPDU_TX_OPERATIONAL:
1655 ista = (struct ath9k_htc_sta *) sta->drv_priv;
1656 ista->tid_state[tid] = AGGR_OPERATIONAL;
1657 break;
1658 default:
1659 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
1660 "Unknown AMPDU action\n");
1661 }
1662
1663 return 0;
1664}
1665
1666static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
1667{
1668 struct ath9k_htc_priv *priv = hw->priv;
1669
1670 mutex_lock(&priv->mutex);
1671 spin_lock_bh(&priv->beacon_lock);
1672 priv->op_flags |= OP_SCANNING;
1673 spin_unlock_bh(&priv->beacon_lock);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301674 cancel_work_sync(&priv->ps_work);
Sujithfb9987d2010-03-17 14:25:25 +05301675 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1676 mutex_unlock(&priv->mutex);
1677}
1678
1679static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
1680{
1681 struct ath9k_htc_priv *priv = hw->priv;
1682
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301683 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301684 mutex_lock(&priv->mutex);
1685 spin_lock_bh(&priv->beacon_lock);
1686 priv->op_flags &= ~OP_SCANNING;
1687 spin_unlock_bh(&priv->beacon_lock);
1688 priv->op_flags |= OP_FULL_RESET;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301689 if (priv->op_flags & OP_ASSOCIATED)
1690 ath9k_htc_beacon_config(priv, NULL);
Sujithfb9987d2010-03-17 14:25:25 +05301691 ath_start_ani(priv);
1692 mutex_unlock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301693 ath9k_htc_ps_restore(priv);
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);
1707 priv->ah->coverage_class = coverage_class;
1708 ath9k_hw_init_global_settings(priv->ah);
1709 mutex_unlock(&priv->mutex);
1710}
1711
1712struct ieee80211_ops ath9k_htc_ops = {
1713 .tx = ath9k_htc_tx,
1714 .start = ath9k_htc_start,
1715 .stop = ath9k_htc_stop,
1716 .add_interface = ath9k_htc_add_interface,
1717 .remove_interface = ath9k_htc_remove_interface,
1718 .config = ath9k_htc_config,
1719 .configure_filter = ath9k_htc_configure_filter,
1720 .sta_notify = ath9k_htc_sta_notify,
1721 .conf_tx = ath9k_htc_conf_tx,
1722 .bss_info_changed = ath9k_htc_bss_info_changed,
1723 .set_key = ath9k_htc_set_key,
1724 .get_tsf = ath9k_htc_get_tsf,
1725 .set_tsf = ath9k_htc_set_tsf,
1726 .reset_tsf = ath9k_htc_reset_tsf,
1727 .ampdu_action = ath9k_htc_ampdu_action,
1728 .sw_scan_start = ath9k_htc_sw_scan_start,
1729 .sw_scan_complete = ath9k_htc_sw_scan_complete,
1730 .set_rts_threshold = ath9k_htc_set_rts_threshold,
1731 .rfkill_poll = ath9k_htc_rfkill_poll_state,
1732 .set_coverage_class = ath9k_htc_set_coverage_class,
1733};