blob: 6d464237d13a4e91c343c25929269704528237d8 [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;
Sujithb4dec5e2010-05-17 12:01:19 +0530370 if (conf_is_ht40(&priv->hw->conf) &&
371 (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40))
Sujithfb9987d2010-03-17 14:25:25 +0530372 caps |= WLAN_RC_SGI_FLAG;
Sujithb4dec5e2010-05-17 12:01:19 +0530373 else if (conf_is_ht20(&priv->hw->conf) &&
374 (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20))
375 caps |= WLAN_RC_SGI_FLAG;
Sujithfb9987d2010-03-17 14:25:25 +0530376 }
377
Sujith0d425a72010-05-17 12:01:16 +0530378 trate->sta_index = ista->index;
379 trate->isnew = 1;
380 trate->capflags = cpu_to_be32(caps);
381}
Sujithfb9987d2010-03-17 14:25:25 +0530382
Sujith0d425a72010-05-17 12:01:16 +0530383static int ath9k_htc_send_rate_cmd(struct ath9k_htc_priv *priv,
384 struct ath9k_htc_target_rate *trate)
385{
386 struct ath_common *common = ath9k_hw_common(priv->ah);
387 int ret;
388 u8 cmd_rsp;
389
390 WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, trate);
Sujithfb9987d2010-03-17 14:25:25 +0530391 if (ret) {
392 ath_print(common, ATH_DBG_FATAL,
393 "Unable to initialize Rate information on target\n");
Sujithfb9987d2010-03-17 14:25:25 +0530394 }
395
Sujith0d425a72010-05-17 12:01:16 +0530396 return ret;
Sujithfb9987d2010-03-17 14:25:25 +0530397}
398
Sujith0d425a72010-05-17 12:01:16 +0530399static void ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
400 struct ieee80211_sta *sta)
Sujithfb9987d2010-03-17 14:25:25 +0530401{
Sujithfb9987d2010-03-17 14:25:25 +0530402 struct ath_common *common = ath9k_hw_common(priv->ah);
Sujith0d425a72010-05-17 12:01:16 +0530403 struct ath9k_htc_target_rate trate;
Sujithfb9987d2010-03-17 14:25:25 +0530404 int ret;
Sujithfb9987d2010-03-17 14:25:25 +0530405
Sujith0d425a72010-05-17 12:01:16 +0530406 memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
407 ath9k_htc_setup_rate(priv, sta, &trate);
408 ret = ath9k_htc_send_rate_cmd(priv, &trate);
409 if (!ret)
410 ath_print(common, ATH_DBG_CONFIG,
411 "Updated target sta: %pM, rate caps: 0x%X\n",
412 sta->addr, be32_to_cpu(trate.capflags));
Sujithfb9987d2010-03-17 14:25:25 +0530413}
414
Sujith2c76ef82010-05-17 12:01:18 +0530415static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv,
416 struct ieee80211_vif *vif,
417 struct ieee80211_bss_conf *bss_conf)
418{
419 struct ath_common *common = ath9k_hw_common(priv->ah);
420 struct ath9k_htc_target_rate trate;
421 struct ieee80211_sta *sta;
422 int ret;
423
424 memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
425
426 rcu_read_lock();
427 sta = ieee80211_find_sta(vif, bss_conf->bssid);
428 if (!sta) {
429 rcu_read_unlock();
430 return;
431 }
432 ath9k_htc_setup_rate(priv, sta, &trate);
433 rcu_read_unlock();
434
435 ret = ath9k_htc_send_rate_cmd(priv, &trate);
436 if (!ret)
437 ath_print(common, ATH_DBG_CONFIG,
438 "Updated target sta: %pM, rate caps: 0x%X\n",
439 bss_conf->bssid, be32_to_cpu(trate.capflags));
440}
441
Sujithfb9987d2010-03-17 14:25:25 +0530442static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
443 struct ieee80211_vif *vif,
444 u8 *sta_addr, u8 tid, bool oper)
445{
446 struct ath_common *common = ath9k_hw_common(priv->ah);
447 struct ath9k_htc_target_aggr aggr;
448 struct ieee80211_sta *sta = NULL;
Dan Carpenter277a64d2010-05-08 18:23:20 +0200449 struct ath9k_htc_sta *ista;
Sujithfb9987d2010-03-17 14:25:25 +0530450 int ret = 0;
451 u8 cmd_rsp;
452
Dan Carpenter0730d112010-05-08 18:24:02 +0200453 if (tid >= ATH9K_HTC_MAX_TID)
Sujithfb9987d2010-03-17 14:25:25 +0530454 return -EINVAL;
455
Sujithfb9987d2010-03-17 14:25:25 +0530456 memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
457
Sujithef98c3c2010-03-29 16:07:11 +0530458 rcu_read_lock();
459
460 /* Check if we are able to retrieve the station */
461 sta = ieee80211_find_sta(vif, sta_addr);
462 if (!sta) {
463 rcu_read_unlock();
464 return -EINVAL;
465 }
466
467 ista = (struct ath9k_htc_sta *) sta->drv_priv;
Sujithfb9987d2010-03-17 14:25:25 +0530468
469 if (oper)
470 ista->tid_state[tid] = AGGR_START;
471 else
472 ista->tid_state[tid] = AGGR_STOP;
473
Sujithef98c3c2010-03-29 16:07:11 +0530474 aggr.sta_index = ista->index;
475
476 rcu_read_unlock();
477
478 aggr.tidno = tid;
479 aggr.aggr_enable = oper;
480
Sujithfb9987d2010-03-17 14:25:25 +0530481 WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
482 if (ret)
483 ath_print(common, ATH_DBG_CONFIG,
484 "Unable to %s TX aggregation for (%pM, %d)\n",
485 (oper) ? "start" : "stop", sta->addr, tid);
486 else
487 ath_print(common, ATH_DBG_CONFIG,
488 "%s aggregation for (%pM, %d)\n",
489 (oper) ? "Starting" : "Stopping", sta->addr, tid);
490
491 return ret;
492}
493
494void ath9k_htc_aggr_work(struct work_struct *work)
495{
496 int ret = 0;
497 struct ath9k_htc_priv *priv =
498 container_of(work, struct ath9k_htc_priv,
499 ath9k_aggr_work.work);
500 struct ath9k_htc_aggr_work *wk = &priv->aggr_work;
501
502 mutex_lock(&wk->mutex);
503
504 switch (wk->action) {
505 case IEEE80211_AMPDU_TX_START:
506 ret = ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
507 wk->tid, true);
508 if (!ret)
509 ieee80211_start_tx_ba_cb(wk->vif, wk->sta_addr,
510 wk->tid);
511 break;
512 case IEEE80211_AMPDU_TX_STOP:
513 ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
514 wk->tid, false);
515 ieee80211_stop_tx_ba_cb(wk->vif, wk->sta_addr, wk->tid);
516 break;
517 default:
518 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
519 "Unknown AMPDU action\n");
520 }
521
522 mutex_unlock(&wk->mutex);
523}
524
525/*********/
526/* DEBUG */
527/*********/
528
529#ifdef CONFIG_ATH9K_HTC_DEBUGFS
530
531static int ath9k_debugfs_open(struct inode *inode, struct file *file)
532{
533 file->private_data = inode->i_private;
534 return 0;
535}
536
537static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
538 size_t count, loff_t *ppos)
539{
540 struct ath9k_htc_priv *priv =
541 (struct ath9k_htc_priv *) file->private_data;
542 struct ath9k_htc_target_stats cmd_rsp;
543 char buf[512];
544 unsigned int len = 0;
545 int ret = 0;
546
547 memset(&cmd_rsp, 0, sizeof(cmd_rsp));
548
549 WMI_CMD(WMI_TGT_STATS_CMDID);
550 if (ret)
551 return -EINVAL;
552
553
554 len += snprintf(buf + len, sizeof(buf) - len,
555 "%19s : %10u\n", "TX Short Retries",
556 be32_to_cpu(cmd_rsp.tx_shortretry));
557 len += snprintf(buf + len, sizeof(buf) - len,
558 "%19s : %10u\n", "TX Long Retries",
559 be32_to_cpu(cmd_rsp.tx_longretry));
560 len += snprintf(buf + len, sizeof(buf) - len,
561 "%19s : %10u\n", "TX Xretries",
562 be32_to_cpu(cmd_rsp.tx_xretries));
563 len += snprintf(buf + len, sizeof(buf) - len,
564 "%19s : %10u\n", "TX Unaggr. Xretries",
565 be32_to_cpu(cmd_rsp.ht_txunaggr_xretry));
566 len += snprintf(buf + len, sizeof(buf) - len,
567 "%19s : %10u\n", "TX Xretries (HT)",
568 be32_to_cpu(cmd_rsp.ht_tx_xretries));
569 len += snprintf(buf + len, sizeof(buf) - len,
570 "%19s : %10u\n", "TX Rate", priv->debug.txrate);
571
572 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
573}
574
575static const struct file_operations fops_tgt_stats = {
576 .read = read_file_tgt_stats,
577 .open = ath9k_debugfs_open,
578 .owner = THIS_MODULE
579};
580
581static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
582 size_t count, loff_t *ppos)
583{
584 struct ath9k_htc_priv *priv =
585 (struct ath9k_htc_priv *) file->private_data;
586 char buf[512];
587 unsigned int len = 0;
588
589 len += snprintf(buf + len, sizeof(buf) - len,
590 "%20s : %10u\n", "Buffers queued",
591 priv->debug.tx_stats.buf_queued);
592 len += snprintf(buf + len, sizeof(buf) - len,
593 "%20s : %10u\n", "Buffers completed",
594 priv->debug.tx_stats.buf_completed);
595 len += snprintf(buf + len, sizeof(buf) - len,
596 "%20s : %10u\n", "SKBs queued",
597 priv->debug.tx_stats.skb_queued);
598 len += snprintf(buf + len, sizeof(buf) - len,
599 "%20s : %10u\n", "SKBs completed",
600 priv->debug.tx_stats.skb_completed);
Sujitheac8e382010-04-16 11:54:00 +0530601 len += snprintf(buf + len, sizeof(buf) - len,
602 "%20s : %10u\n", "SKBs dropped",
603 priv->debug.tx_stats.skb_dropped);
Sujithfb9987d2010-03-17 14:25:25 +0530604
Sujith2edb4582010-05-14 11:18:54 +0530605 len += snprintf(buf + len, sizeof(buf) - len,
606 "%20s : %10u\n", "BE queued",
607 priv->debug.tx_stats.queue_stats[WME_AC_BE]);
608 len += snprintf(buf + len, sizeof(buf) - len,
609 "%20s : %10u\n", "BK queued",
610 priv->debug.tx_stats.queue_stats[WME_AC_BK]);
611 len += snprintf(buf + len, sizeof(buf) - len,
612 "%20s : %10u\n", "VI queued",
613 priv->debug.tx_stats.queue_stats[WME_AC_VI]);
614 len += snprintf(buf + len, sizeof(buf) - len,
615 "%20s : %10u\n", "VO queued",
616 priv->debug.tx_stats.queue_stats[WME_AC_VO]);
617
Sujithfb9987d2010-03-17 14:25:25 +0530618 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
619}
620
621static const struct file_operations fops_xmit = {
622 .read = read_file_xmit,
623 .open = ath9k_debugfs_open,
624 .owner = THIS_MODULE
625};
626
627static ssize_t read_file_recv(struct file *file, char __user *user_buf,
628 size_t count, loff_t *ppos)
629{
630 struct ath9k_htc_priv *priv =
631 (struct ath9k_htc_priv *) file->private_data;
632 char buf[512];
633 unsigned int len = 0;
634
635 len += snprintf(buf + len, sizeof(buf) - len,
636 "%20s : %10u\n", "SKBs allocated",
637 priv->debug.rx_stats.skb_allocated);
638 len += snprintf(buf + len, sizeof(buf) - len,
639 "%20s : %10u\n", "SKBs completed",
640 priv->debug.rx_stats.skb_completed);
641 len += snprintf(buf + len, sizeof(buf) - len,
642 "%20s : %10u\n", "SKBs Dropped",
643 priv->debug.rx_stats.skb_dropped);
644
645 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
646}
647
648static const struct file_operations fops_recv = {
649 .read = read_file_recv,
650 .open = ath9k_debugfs_open,
651 .owner = THIS_MODULE
652};
653
Sujithe1572c52010-03-24 13:42:13 +0530654int ath9k_htc_init_debug(struct ath_hw *ah)
Sujithfb9987d2010-03-17 14:25:25 +0530655{
656 struct ath_common *common = ath9k_hw_common(ah);
657 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
658
659 if (!ath9k_debugfs_root)
660 return -ENOENT;
661
662 priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy),
663 ath9k_debugfs_root);
664 if (!priv->debug.debugfs_phy)
665 goto err;
666
667 priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR,
668 priv->debug.debugfs_phy,
669 priv, &fops_tgt_stats);
670 if (!priv->debug.debugfs_tgt_stats)
671 goto err;
672
673
674 priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR,
675 priv->debug.debugfs_phy,
676 priv, &fops_xmit);
677 if (!priv->debug.debugfs_xmit)
678 goto err;
679
680 priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR,
681 priv->debug.debugfs_phy,
682 priv, &fops_recv);
683 if (!priv->debug.debugfs_recv)
684 goto err;
685
686 return 0;
687
688err:
Sujithe1572c52010-03-24 13:42:13 +0530689 ath9k_htc_exit_debug(ah);
Sujithfb9987d2010-03-17 14:25:25 +0530690 return -ENOMEM;
691}
692
Sujithe1572c52010-03-24 13:42:13 +0530693void ath9k_htc_exit_debug(struct ath_hw *ah)
Sujithfb9987d2010-03-17 14:25:25 +0530694{
695 struct ath_common *common = ath9k_hw_common(ah);
696 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
697
698 debugfs_remove(priv->debug.debugfs_recv);
699 debugfs_remove(priv->debug.debugfs_xmit);
700 debugfs_remove(priv->debug.debugfs_tgt_stats);
701 debugfs_remove(priv->debug.debugfs_phy);
702}
703
Sujithe1572c52010-03-24 13:42:13 +0530704int ath9k_htc_debug_create_root(void)
Sujithfb9987d2010-03-17 14:25:25 +0530705{
706 ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
707 if (!ath9k_debugfs_root)
708 return -ENOENT;
709
710 return 0;
711}
712
Sujithe1572c52010-03-24 13:42:13 +0530713void ath9k_htc_debug_remove_root(void)
Sujithfb9987d2010-03-17 14:25:25 +0530714{
715 debugfs_remove(ath9k_debugfs_root);
716 ath9k_debugfs_root = NULL;
717}
718
719#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
720
721/*******/
722/* ANI */
723/*******/
724
725static void ath_start_ani(struct ath9k_htc_priv *priv)
726{
727 struct ath_common *common = ath9k_hw_common(priv->ah);
728 unsigned long timestamp = jiffies_to_msecs(jiffies);
729
730 common->ani.longcal_timer = timestamp;
731 common->ani.shortcal_timer = timestamp;
732 common->ani.checkani_timer = timestamp;
733
734 ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
735 msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
736}
737
738void ath9k_ani_work(struct work_struct *work)
739{
740 struct ath9k_htc_priv *priv =
741 container_of(work, struct ath9k_htc_priv,
742 ath9k_ani_work.work);
743 struct ath_hw *ah = priv->ah;
744 struct ath_common *common = ath9k_hw_common(ah);
745 bool longcal = false;
746 bool shortcal = false;
747 bool aniflag = false;
748 unsigned int timestamp = jiffies_to_msecs(jiffies);
749 u32 cal_interval, short_cal_interval;
750
751 short_cal_interval = ATH_STA_SHORT_CALINTERVAL;
752
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530753 /* Only calibrate if awake */
754 if (ah->power_mode != ATH9K_PM_AWAKE)
755 goto set_timer;
756
Sujithfb9987d2010-03-17 14:25:25 +0530757 /* Long calibration runs independently of short calibration. */
758 if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
759 longcal = true;
760 ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
761 common->ani.longcal_timer = timestamp;
762 }
763
764 /* Short calibration applies only while caldone is false */
765 if (!common->ani.caldone) {
766 if ((timestamp - common->ani.shortcal_timer) >=
767 short_cal_interval) {
768 shortcal = true;
769 ath_print(common, ATH_DBG_ANI,
770 "shortcal @%lu\n", jiffies);
771 common->ani.shortcal_timer = timestamp;
772 common->ani.resetcal_timer = timestamp;
773 }
774 } else {
775 if ((timestamp - common->ani.resetcal_timer) >=
776 ATH_RESTART_CALINTERVAL) {
777 common->ani.caldone = ath9k_hw_reset_calvalid(ah);
778 if (common->ani.caldone)
779 common->ani.resetcal_timer = timestamp;
780 }
781 }
782
783 /* Verify whether we must check ANI */
784 if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
785 aniflag = true;
786 common->ani.checkani_timer = timestamp;
787 }
788
789 /* Skip all processing if there's nothing to do. */
790 if (longcal || shortcal || aniflag) {
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530791
792 ath9k_htc_ps_wakeup(priv);
793
Sujithfb9987d2010-03-17 14:25:25 +0530794 /* Call ANI routine if necessary */
795 if (aniflag)
796 ath9k_hw_ani_monitor(ah, ah->curchan);
797
798 /* Perform calibration if necessary */
799 if (longcal || shortcal) {
800 common->ani.caldone =
801 ath9k_hw_calibrate(ah, ah->curchan,
802 common->rx_chainmask,
803 longcal);
804
805 if (longcal)
806 common->ani.noise_floor =
807 ath9k_hw_getchan_noise(ah, ah->curchan);
808
809 ath_print(common, ATH_DBG_ANI,
810 " calibrate chan %u/%x nf: %d\n",
811 ah->curchan->channel,
812 ah->curchan->channelFlags,
813 common->ani.noise_floor);
814 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530815
816 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530817 }
818
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530819set_timer:
Sujithfb9987d2010-03-17 14:25:25 +0530820 /*
821 * Set timer interval based on previous results.
822 * The interval must be the shortest necessary to satisfy ANI,
823 * short calibration and long calibration.
824 */
825 cal_interval = ATH_LONG_CALINTERVAL;
826 if (priv->ah->config.enable_ani)
827 cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
828 if (!common->ani.caldone)
829 cal_interval = min(cal_interval, (u32)short_cal_interval);
830
831 ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
832 msecs_to_jiffies(cal_interval));
833}
834
835/*******/
836/* LED */
837/*******/
838
839static void ath9k_led_blink_work(struct work_struct *work)
840{
841 struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
842 ath9k_led_blink_work.work);
843
844 if (!(priv->op_flags & OP_LED_ASSOCIATED))
845 return;
846
847 if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
848 (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
849 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
850 else
851 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
852 (priv->op_flags & OP_LED_ON) ? 1 : 0);
853
854 ieee80211_queue_delayed_work(priv->hw,
855 &priv->ath9k_led_blink_work,
856 (priv->op_flags & OP_LED_ON) ?
857 msecs_to_jiffies(priv->led_off_duration) :
858 msecs_to_jiffies(priv->led_on_duration));
859
860 priv->led_on_duration = priv->led_on_cnt ?
861 max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
862 ATH_LED_ON_DURATION_IDLE;
863 priv->led_off_duration = priv->led_off_cnt ?
864 max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
865 ATH_LED_OFF_DURATION_IDLE;
866 priv->led_on_cnt = priv->led_off_cnt = 0;
867
868 if (priv->op_flags & OP_LED_ON)
869 priv->op_flags &= ~OP_LED_ON;
870 else
871 priv->op_flags |= OP_LED_ON;
872}
873
874static void ath9k_led_brightness_work(struct work_struct *work)
875{
876 struct ath_led *led = container_of(work, struct ath_led,
877 brightness_work.work);
878 struct ath9k_htc_priv *priv = led->priv;
879
880 switch (led->brightness) {
881 case LED_OFF:
882 if (led->led_type == ATH_LED_ASSOC ||
883 led->led_type == ATH_LED_RADIO) {
884 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
885 (led->led_type == ATH_LED_RADIO));
886 priv->op_flags &= ~OP_LED_ASSOCIATED;
887 if (led->led_type == ATH_LED_RADIO)
888 priv->op_flags &= ~OP_LED_ON;
889 } else {
890 priv->led_off_cnt++;
891 }
892 break;
893 case LED_FULL:
894 if (led->led_type == ATH_LED_ASSOC) {
895 priv->op_flags |= OP_LED_ASSOCIATED;
896 ieee80211_queue_delayed_work(priv->hw,
897 &priv->ath9k_led_blink_work, 0);
898 } else if (led->led_type == ATH_LED_RADIO) {
899 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
900 priv->op_flags |= OP_LED_ON;
901 } else {
902 priv->led_on_cnt++;
903 }
904 break;
905 default:
906 break;
907 }
908}
909
910static void ath9k_led_brightness(struct led_classdev *led_cdev,
911 enum led_brightness brightness)
912{
913 struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
914 struct ath9k_htc_priv *priv = led->priv;
915
916 led->brightness = brightness;
917 if (!(priv->op_flags & OP_LED_DEINIT))
918 ieee80211_queue_delayed_work(priv->hw,
919 &led->brightness_work, 0);
920}
921
922static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
923{
924 cancel_delayed_work_sync(&priv->radio_led.brightness_work);
925 cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
926 cancel_delayed_work_sync(&priv->tx_led.brightness_work);
927 cancel_delayed_work_sync(&priv->rx_led.brightness_work);
928}
929
930static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
931 char *trigger)
932{
933 int ret;
934
935 led->priv = priv;
936 led->led_cdev.name = led->name;
937 led->led_cdev.default_trigger = trigger;
938 led->led_cdev.brightness_set = ath9k_led_brightness;
939
940 ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
941 if (ret)
942 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
943 "Failed to register led:%s", led->name);
944 else
945 led->registered = 1;
946
947 INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
948
949 return ret;
950}
951
952static void ath9k_unregister_led(struct ath_led *led)
953{
954 if (led->registered) {
955 led_classdev_unregister(&led->led_cdev);
956 led->registered = 0;
957 }
958}
959
960void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
961{
962 priv->op_flags |= OP_LED_DEINIT;
963 ath9k_unregister_led(&priv->assoc_led);
964 priv->op_flags &= ~OP_LED_ASSOCIATED;
965 ath9k_unregister_led(&priv->tx_led);
966 ath9k_unregister_led(&priv->rx_led);
967 ath9k_unregister_led(&priv->radio_led);
Sujithfb9987d2010-03-17 14:25:25 +0530968}
969
970void ath9k_init_leds(struct ath9k_htc_priv *priv)
971{
972 char *trigger;
973 int ret;
974
975 if (AR_SREV_9287(priv->ah))
976 priv->ah->led_pin = ATH_LED_PIN_9287;
977 else if (AR_SREV_9271(priv->ah))
978 priv->ah->led_pin = ATH_LED_PIN_9271;
979 else
980 priv->ah->led_pin = ATH_LED_PIN_DEF;
981
982 /* Configure gpio 1 for output */
983 ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
984 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
985 /* LED off, active low */
986 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
987
988 INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
989
990 trigger = ieee80211_get_radio_led_name(priv->hw);
991 snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
992 "ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
993 ret = ath9k_register_led(priv, &priv->radio_led, trigger);
994 priv->radio_led.led_type = ATH_LED_RADIO;
995 if (ret)
996 goto fail;
997
998 trigger = ieee80211_get_assoc_led_name(priv->hw);
999 snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
1000 "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
1001 ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
1002 priv->assoc_led.led_type = ATH_LED_ASSOC;
1003 if (ret)
1004 goto fail;
1005
1006 trigger = ieee80211_get_tx_led_name(priv->hw);
1007 snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
1008 "ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
1009 ret = ath9k_register_led(priv, &priv->tx_led, trigger);
1010 priv->tx_led.led_type = ATH_LED_TX;
1011 if (ret)
1012 goto fail;
1013
1014 trigger = ieee80211_get_rx_led_name(priv->hw);
1015 snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
1016 "ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
1017 ret = ath9k_register_led(priv, &priv->rx_led, trigger);
1018 priv->rx_led.led_type = ATH_LED_RX;
1019 if (ret)
1020 goto fail;
1021
1022 priv->op_flags &= ~OP_LED_DEINIT;
1023
1024 return;
1025
1026fail:
1027 cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
1028 ath9k_deinit_leds(priv);
1029}
1030
1031/*******************/
1032/* Rfkill */
1033/*******************/
1034
1035static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
1036{
1037 return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
1038 priv->ah->rfkill_polarity;
1039}
1040
1041static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
1042{
1043 struct ath9k_htc_priv *priv = hw->priv;
1044 bool blocked = !!ath_is_rfkill_set(priv);
1045
1046 wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
1047}
1048
1049void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
1050{
1051 if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
1052 wiphy_rfkill_start_polling(priv->hw->wiphy);
1053}
1054
1055/**********************/
1056/* mac80211 Callbacks */
1057/**********************/
1058
1059static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1060{
1061 struct ieee80211_hdr *hdr;
1062 struct ath9k_htc_priv *priv = hw->priv;
Sujith7757dfe2010-03-29 16:07:17 +05301063 int padpos, padsize, ret;
Sujithfb9987d2010-03-17 14:25:25 +05301064
1065 hdr = (struct ieee80211_hdr *) skb->data;
1066
1067 /* Add the padding after the header if this is not already done */
1068 padpos = ath9k_cmn_padpos(hdr->frame_control);
1069 padsize = padpos & 3;
1070 if (padsize && skb->len > padpos) {
1071 if (skb_headroom(skb) < padsize)
1072 return -1;
1073 skb_push(skb, padsize);
1074 memmove(skb->data, skb->data + padsize, padpos);
1075 }
1076
Sujith7757dfe2010-03-29 16:07:17 +05301077 ret = ath9k_htc_tx_start(priv, skb);
1078 if (ret != 0) {
1079 if (ret == -ENOMEM) {
1080 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1081 "Stopping TX queues\n");
1082 ieee80211_stop_queues(hw);
1083 spin_lock_bh(&priv->tx_lock);
1084 priv->tx_queues_stop = true;
1085 spin_unlock_bh(&priv->tx_lock);
1086 } else {
1087 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1088 "Tx failed");
1089 }
Sujithfb9987d2010-03-17 14:25:25 +05301090 goto fail_tx;
1091 }
1092
1093 return 0;
1094
1095fail_tx:
1096 dev_kfree_skb_any(skb);
1097 return 0;
1098}
1099
Sujith2ff65752010-05-07 13:37:57 +05301100static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led)
Sujithfb9987d2010-03-17 14:25:25 +05301101{
1102 struct ath9k_htc_priv *priv = hw->priv;
1103 struct ath_hw *ah = priv->ah;
1104 struct ath_common *common = ath9k_hw_common(ah);
1105 struct ieee80211_channel *curchan = hw->conf.channel;
1106 struct ath9k_channel *init_channel;
1107 int ret = 0;
1108 enum htc_phymode mode;
Sujith7f1f5a02010-04-16 11:54:03 +05301109 __be16 htc_mode;
Sujithfb9987d2010-03-17 14:25:25 +05301110 u8 cmd_rsp;
1111
1112 ath_print(common, ATH_DBG_CONFIG,
1113 "Starting driver with initial channel: %d MHz\n",
1114 curchan->center_freq);
1115
Sujithfb9987d2010-03-17 14:25:25 +05301116 /* setup initial channel */
1117 init_channel = ath9k_cmn_get_curchannel(hw, ah);
1118
1119 /* Reset SERDES registers */
1120 ath9k_hw_configpcipowersave(ah, 0, 0);
1121
1122 ath9k_hw_htc_resetinit(ah);
1123 ret = ath9k_hw_reset(ah, init_channel, false);
1124 if (ret) {
1125 ath_print(common, ATH_DBG_FATAL,
1126 "Unable to reset hardware; reset status %d "
1127 "(freq %u MHz)\n", ret, curchan->center_freq);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301128 return ret;
Sujithfb9987d2010-03-17 14:25:25 +05301129 }
1130
1131 ath_update_txpow(priv);
1132
1133 mode = ath9k_htc_get_curmode(priv, init_channel);
1134 htc_mode = cpu_to_be16(mode);
1135 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
Sujithfb9987d2010-03-17 14:25:25 +05301136 WMI_CMD(WMI_ATH_INIT_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301137 WMI_CMD(WMI_START_RECV_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301138
1139 ath9k_host_rx_init(priv);
1140
1141 priv->op_flags &= ~OP_INVALID;
1142 htc_start(priv->htc);
1143
Sujith7757dfe2010-03-29 16:07:17 +05301144 spin_lock_bh(&priv->tx_lock);
1145 priv->tx_queues_stop = false;
1146 spin_unlock_bh(&priv->tx_lock);
1147
Sujith2ff65752010-05-07 13:37:57 +05301148 if (led) {
1149 /* Enable LED */
1150 ath9k_hw_cfg_output(ah, ah->led_pin,
1151 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
1152 ath9k_hw_set_gpio(ah, ah->led_pin, 0);
1153 }
1154
Sujith7757dfe2010-03-29 16:07:17 +05301155 ieee80211_wake_queues(hw);
1156
Sujithfb9987d2010-03-17 14:25:25 +05301157 return ret;
1158}
1159
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301160static int ath9k_htc_start(struct ieee80211_hw *hw)
1161{
1162 struct ath9k_htc_priv *priv = hw->priv;
1163 int ret = 0;
1164
1165 mutex_lock(&priv->mutex);
Sujith2ff65752010-05-07 13:37:57 +05301166 ret = ath9k_htc_radio_enable(hw, false);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301167 mutex_unlock(&priv->mutex);
1168
1169 return ret;
1170}
1171
Sujith2ff65752010-05-07 13:37:57 +05301172static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led)
Sujithfb9987d2010-03-17 14:25:25 +05301173{
1174 struct ath9k_htc_priv *priv = hw->priv;
1175 struct ath_hw *ah = priv->ah;
1176 struct ath_common *common = ath9k_hw_common(ah);
1177 int ret = 0;
1178 u8 cmd_rsp;
1179
Sujithfb9987d2010-03-17 14:25:25 +05301180 if (priv->op_flags & OP_INVALID) {
1181 ath_print(common, ATH_DBG_ANY, "Device not present\n");
Sujithfb9987d2010-03-17 14:25:25 +05301182 return;
1183 }
1184
Sujith2ff65752010-05-07 13:37:57 +05301185 if (led) {
1186 /* Disable LED */
1187 ath9k_hw_set_gpio(ah, ah->led_pin, 1);
1188 ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
1189 }
1190
Sujith7073daa2010-04-23 10:28:13 +05301191 /* Cancel all the running timers/work .. */
1192 cancel_work_sync(&priv->ps_work);
1193 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1194 cancel_delayed_work_sync(&priv->ath9k_aggr_work);
1195 cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
1196 ath9k_led_stop_brightness(priv);
1197
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301198 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301199 htc_stop(priv->htc);
1200 WMI_CMD(WMI_DISABLE_INTR_CMDID);
1201 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
1202 WMI_CMD(WMI_STOP_RECV_CMDID);
1203 ath9k_hw_phy_disable(ah);
1204 ath9k_hw_disable(ah);
1205 ath9k_hw_configpcipowersave(ah, 1, 1);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301206 ath9k_htc_ps_restore(priv);
1207 ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
Sujithfb9987d2010-03-17 14:25:25 +05301208
Sujithfb9987d2010-03-17 14:25:25 +05301209 skb_queue_purge(&priv->tx_queue);
1210
1211 /* Remove monitor interface here */
1212 if (ah->opmode == NL80211_IFTYPE_MONITOR) {
1213 if (ath9k_htc_remove_monitor_interface(priv))
1214 ath_print(common, ATH_DBG_FATAL,
1215 "Unable to remove monitor interface\n");
1216 else
1217 ath_print(common, ATH_DBG_CONFIG,
1218 "Monitor interface removed\n");
1219 }
1220
1221 priv->op_flags |= OP_INVALID;
Sujithfb9987d2010-03-17 14:25:25 +05301222
1223 ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
1224}
1225
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301226static void ath9k_htc_stop(struct ieee80211_hw *hw)
1227{
1228 struct ath9k_htc_priv *priv = hw->priv;
1229
1230 mutex_lock(&priv->mutex);
Sujith2ff65752010-05-07 13:37:57 +05301231 ath9k_htc_radio_disable(hw, false);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301232 mutex_unlock(&priv->mutex);
1233}
1234
1235
Sujithfb9987d2010-03-17 14:25:25 +05301236static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
1237 struct ieee80211_vif *vif)
1238{
1239 struct ath9k_htc_priv *priv = hw->priv;
1240 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1241 struct ath_common *common = ath9k_hw_common(priv->ah);
1242 struct ath9k_htc_target_vif hvif;
1243 int ret = 0;
1244 u8 cmd_rsp;
1245
1246 mutex_lock(&priv->mutex);
1247
1248 /* Only one interface for now */
1249 if (priv->nvifs > 0) {
1250 ret = -ENOBUFS;
1251 goto out;
1252 }
1253
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301254 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301255 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1256 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1257
1258 switch (vif->type) {
1259 case NL80211_IFTYPE_STATION:
1260 hvif.opmode = cpu_to_be32(HTC_M_STA);
1261 break;
1262 case NL80211_IFTYPE_ADHOC:
1263 hvif.opmode = cpu_to_be32(HTC_M_IBSS);
1264 break;
1265 default:
1266 ath_print(common, ATH_DBG_FATAL,
1267 "Interface type %d not yet supported\n", vif->type);
1268 ret = -EOPNOTSUPP;
1269 goto out;
1270 }
1271
1272 ath_print(common, ATH_DBG_CONFIG,
1273 "Attach a VIF of type: %d\n", vif->type);
1274
1275 priv->ah->opmode = vif->type;
1276
1277 /* Index starts from zero on the target */
1278 avp->index = hvif.index = priv->nvifs;
1279 hvif.rtsthreshold = cpu_to_be16(2304);
1280 WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
1281 if (ret)
1282 goto out;
1283
1284 priv->nvifs++;
1285
1286 /*
1287 * We need a node in target to tx mgmt frames
1288 * before association.
1289 */
1290 ret = ath9k_htc_add_station(priv, vif, NULL);
1291 if (ret)
1292 goto out;
1293
1294 ret = ath9k_htc_update_cap_target(priv);
1295 if (ret)
1296 ath_print(common, ATH_DBG_CONFIG, "Failed to update"
1297 " capability in target \n");
1298
1299 priv->vif = vif;
1300out:
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301301 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301302 mutex_unlock(&priv->mutex);
1303 return ret;
1304}
1305
1306static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
1307 struct ieee80211_vif *vif)
1308{
1309 struct ath9k_htc_priv *priv = hw->priv;
1310 struct ath_common *common = ath9k_hw_common(priv->ah);
1311 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1312 struct ath9k_htc_target_vif hvif;
1313 int ret = 0;
1314 u8 cmd_rsp;
1315
1316 ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
1317
1318 mutex_lock(&priv->mutex);
1319
1320 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1321 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1322 hvif.index = avp->index;
1323 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
1324 priv->nvifs--;
1325
1326 ath9k_htc_remove_station(priv, vif, NULL);
Sujithfb9987d2010-03-17 14:25:25 +05301327 priv->vif = NULL;
1328
1329 mutex_unlock(&priv->mutex);
1330}
1331
1332static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
1333{
1334 struct ath9k_htc_priv *priv = hw->priv;
1335 struct ath_common *common = ath9k_hw_common(priv->ah);
1336 struct ieee80211_conf *conf = &hw->conf;
1337
1338 mutex_lock(&priv->mutex);
1339
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301340 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1341 bool enable_radio = false;
1342 bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
1343
1344 if (!idle && priv->ps_idle)
1345 enable_radio = true;
1346
1347 priv->ps_idle = idle;
1348
1349 if (enable_radio) {
1350 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
Sujith2ff65752010-05-07 13:37:57 +05301351 ath9k_htc_radio_enable(hw, true);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301352 ath_print(common, ATH_DBG_CONFIG,
1353 "not-idle: enabling radio\n");
1354 }
1355 }
1356
Sujithfb9987d2010-03-17 14:25:25 +05301357 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1358 struct ieee80211_channel *curchan = hw->conf.channel;
1359 int pos = curchan->hw_value;
Sujithfb9987d2010-03-17 14:25:25 +05301360
1361 ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
1362 curchan->center_freq);
1363
Sujithfb9987d2010-03-17 14:25:25 +05301364 ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
1365
1366 if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
1367 ath_print(common, ATH_DBG_FATAL,
1368 "Unable to set channel\n");
1369 mutex_unlock(&priv->mutex);
1370 return -EINVAL;
1371 }
1372
1373 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301374 if (changed & IEEE80211_CONF_CHANGE_PS) {
1375 if (conf->flags & IEEE80211_CONF_PS) {
1376 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
1377 priv->ps_enabled = true;
1378 } else {
1379 priv->ps_enabled = false;
1380 cancel_work_sync(&priv->ps_work);
1381 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1382 }
1383 }
Sujithfb9987d2010-03-17 14:25:25 +05301384
1385 if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
1386 if (conf->flags & IEEE80211_CONF_MONITOR) {
1387 if (ath9k_htc_add_monitor_interface(priv))
1388 ath_print(common, ATH_DBG_FATAL,
1389 "Failed to set monitor mode\n");
1390 else
1391 ath_print(common, ATH_DBG_CONFIG,
1392 "HW opmode set to Monitor mode\n");
1393 }
1394 }
1395
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301396 if (priv->ps_idle) {
1397 ath_print(common, ATH_DBG_CONFIG,
1398 "idle: disabling radio\n");
Sujith2ff65752010-05-07 13:37:57 +05301399 ath9k_htc_radio_disable(hw, true);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301400 }
1401
Sujithfb9987d2010-03-17 14:25:25 +05301402 mutex_unlock(&priv->mutex);
1403
1404 return 0;
1405}
1406
1407#define SUPPORTED_FILTERS \
1408 (FIF_PROMISC_IN_BSS | \
1409 FIF_ALLMULTI | \
1410 FIF_CONTROL | \
1411 FIF_PSPOLL | \
1412 FIF_OTHER_BSS | \
1413 FIF_BCN_PRBRESP_PROMISC | \
1414 FIF_FCSFAIL)
1415
1416static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
1417 unsigned int changed_flags,
1418 unsigned int *total_flags,
1419 u64 multicast)
1420{
1421 struct ath9k_htc_priv *priv = hw->priv;
1422 u32 rfilt;
1423
1424 mutex_lock(&priv->mutex);
1425
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301426 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301427 changed_flags &= SUPPORTED_FILTERS;
1428 *total_flags &= SUPPORTED_FILTERS;
1429
1430 priv->rxfilter = *total_flags;
Sujith0995d112010-03-29 16:07:09 +05301431 rfilt = ath9k_htc_calcrxfilter(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301432 ath9k_hw_setrxfilter(priv->ah, rfilt);
1433
1434 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
1435 "Set HW RX filter: 0x%x\n", rfilt);
1436
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301437 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301438 mutex_unlock(&priv->mutex);
1439}
1440
1441static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
1442 struct ieee80211_vif *vif,
1443 enum sta_notify_cmd cmd,
1444 struct ieee80211_sta *sta)
1445{
1446 struct ath9k_htc_priv *priv = hw->priv;
1447 int ret;
1448
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301449 mutex_lock(&priv->mutex);
1450
Sujithfb9987d2010-03-17 14:25:25 +05301451 switch (cmd) {
1452 case STA_NOTIFY_ADD:
1453 ret = ath9k_htc_add_station(priv, vif, sta);
1454 if (!ret)
Sujith0d425a72010-05-17 12:01:16 +05301455 ath9k_htc_init_rate(priv, sta);
Sujithfb9987d2010-03-17 14:25:25 +05301456 break;
1457 case STA_NOTIFY_REMOVE:
1458 ath9k_htc_remove_station(priv, vif, sta);
1459 break;
1460 default:
1461 break;
1462 }
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301463
1464 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301465}
1466
1467static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
1468 const struct ieee80211_tx_queue_params *params)
1469{
1470 struct ath9k_htc_priv *priv = hw->priv;
1471 struct ath_common *common = ath9k_hw_common(priv->ah);
1472 struct ath9k_tx_queue_info qi;
1473 int ret = 0, qnum;
1474
1475 if (queue >= WME_NUM_AC)
1476 return 0;
1477
1478 mutex_lock(&priv->mutex);
1479
1480 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
1481
1482 qi.tqi_aifs = params->aifs;
1483 qi.tqi_cwmin = params->cw_min;
1484 qi.tqi_cwmax = params->cw_max;
1485 qi.tqi_burstTime = params->txop;
1486
1487 qnum = get_hw_qnum(queue, priv->hwq_map);
1488
1489 ath_print(common, ATH_DBG_CONFIG,
1490 "Configure tx [queue/hwq] [%d/%d], "
1491 "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
1492 queue, qnum, params->aifs, params->cw_min,
1493 params->cw_max, params->txop);
1494
Sujithe1572c52010-03-24 13:42:13 +05301495 ret = ath_htc_txq_update(priv, qnum, &qi);
Sujithfb9987d2010-03-17 14:25:25 +05301496 if (ret)
1497 ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
1498
1499 mutex_unlock(&priv->mutex);
1500
1501 return ret;
1502}
1503
1504static int ath9k_htc_set_key(struct ieee80211_hw *hw,
1505 enum set_key_cmd cmd,
1506 struct ieee80211_vif *vif,
1507 struct ieee80211_sta *sta,
1508 struct ieee80211_key_conf *key)
1509{
1510 struct ath9k_htc_priv *priv = hw->priv;
1511 struct ath_common *common = ath9k_hw_common(priv->ah);
1512 int ret = 0;
1513
Sujithe1572c52010-03-24 13:42:13 +05301514 if (htc_modparam_nohwcrypt)
Sujithfb9987d2010-03-17 14:25:25 +05301515 return -ENOSPC;
1516
1517 mutex_lock(&priv->mutex);
1518 ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301519 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301520
1521 switch (cmd) {
1522 case SET_KEY:
1523 ret = ath9k_cmn_key_config(common, vif, sta, key);
1524 if (ret >= 0) {
1525 key->hw_key_idx = ret;
1526 /* push IV and Michael MIC generation to stack */
1527 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
1528 if (key->alg == ALG_TKIP)
1529 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
1530 if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
1531 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
1532 ret = 0;
1533 }
1534 break;
1535 case DISABLE_KEY:
1536 ath9k_cmn_key_delete(common, key);
1537 break;
1538 default:
1539 ret = -EINVAL;
1540 }
1541
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301542 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301543 mutex_unlock(&priv->mutex);
1544
1545 return ret;
1546}
1547
1548static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
1549 struct ieee80211_vif *vif,
1550 struct ieee80211_bss_conf *bss_conf,
1551 u32 changed)
1552{
1553 struct ath9k_htc_priv *priv = hw->priv;
1554 struct ath_hw *ah = priv->ah;
1555 struct ath_common *common = ath9k_hw_common(ah);
1556
1557 mutex_lock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301558 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301559
1560 if (changed & BSS_CHANGED_ASSOC) {
1561 common->curaid = bss_conf->assoc ?
1562 bss_conf->aid : 0;
1563 ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
1564 bss_conf->assoc);
1565
1566 if (bss_conf->assoc) {
1567 priv->op_flags |= OP_ASSOCIATED;
1568 ath_start_ani(priv);
1569 } else {
1570 priv->op_flags &= ~OP_ASSOCIATED;
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301571 cancel_work_sync(&priv->ps_work);
Sujithfb9987d2010-03-17 14:25:25 +05301572 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1573 }
1574 }
1575
1576 if (changed & BSS_CHANGED_BSSID) {
1577 /* Set BSSID */
1578 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1579 ath9k_hw_write_associd(ah);
1580
1581 ath_print(common, ATH_DBG_CONFIG,
1582 "BSSID: %pM aid: 0x%x\n",
1583 common->curbssid, common->curaid);
1584 }
1585
1586 if ((changed & BSS_CHANGED_BEACON_INT) ||
1587 (changed & BSS_CHANGED_BEACON) ||
1588 ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1589 bss_conf->enable_beacon)) {
1590 priv->op_flags |= OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301591 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301592 }
1593
Sujithfb9987d2010-03-17 14:25:25 +05301594 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1595 !bss_conf->enable_beacon) {
1596 priv->op_flags &= ~OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301597 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301598 }
1599
1600 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1601 ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
1602 bss_conf->use_short_preamble);
1603 if (bss_conf->use_short_preamble)
1604 priv->op_flags |= OP_PREAMBLE_SHORT;
1605 else
1606 priv->op_flags &= ~OP_PREAMBLE_SHORT;
1607 }
1608
1609 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1610 ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
1611 bss_conf->use_cts_prot);
1612 if (bss_conf->use_cts_prot &&
1613 hw->conf.channel->band != IEEE80211_BAND_5GHZ)
1614 priv->op_flags |= OP_PROTECT_ENABLE;
1615 else
1616 priv->op_flags &= ~OP_PROTECT_ENABLE;
1617 }
1618
1619 if (changed & BSS_CHANGED_ERP_SLOT) {
1620 if (bss_conf->use_short_slot)
1621 ah->slottime = 9;
1622 else
1623 ah->slottime = 20;
1624
1625 ath9k_hw_init_global_settings(ah);
1626 }
1627
Sujith2c76ef82010-05-17 12:01:18 +05301628 if (changed & BSS_CHANGED_HT)
1629 ath9k_htc_update_rate(priv, vif, bss_conf);
1630
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301631 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301632 mutex_unlock(&priv->mutex);
1633}
1634
1635static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
1636{
1637 struct ath9k_htc_priv *priv = hw->priv;
1638 u64 tsf;
1639
1640 mutex_lock(&priv->mutex);
1641 tsf = ath9k_hw_gettsf64(priv->ah);
1642 mutex_unlock(&priv->mutex);
1643
1644 return tsf;
1645}
1646
1647static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
1648{
1649 struct ath9k_htc_priv *priv = hw->priv;
1650
1651 mutex_lock(&priv->mutex);
1652 ath9k_hw_settsf64(priv->ah, tsf);
1653 mutex_unlock(&priv->mutex);
1654}
1655
1656static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
1657{
1658 struct ath9k_htc_priv *priv = hw->priv;
1659
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301660 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301661 mutex_lock(&priv->mutex);
1662 ath9k_hw_reset_tsf(priv->ah);
1663 mutex_unlock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301664 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301665}
1666
1667static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
1668 struct ieee80211_vif *vif,
1669 enum ieee80211_ampdu_mlme_action action,
1670 struct ieee80211_sta *sta,
1671 u16 tid, u16 *ssn)
1672{
1673 struct ath9k_htc_priv *priv = hw->priv;
1674 struct ath9k_htc_aggr_work *work = &priv->aggr_work;
1675 struct ath9k_htc_sta *ista;
1676
1677 switch (action) {
1678 case IEEE80211_AMPDU_RX_START:
1679 break;
1680 case IEEE80211_AMPDU_RX_STOP:
1681 break;
1682 case IEEE80211_AMPDU_TX_START:
1683 case IEEE80211_AMPDU_TX_STOP:
1684 if (!(priv->op_flags & OP_TXAGGR))
1685 return -ENOTSUPP;
1686 memcpy(work->sta_addr, sta->addr, ETH_ALEN);
1687 work->hw = hw;
1688 work->vif = vif;
1689 work->action = action;
1690 work->tid = tid;
1691 ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0);
1692 break;
1693 case IEEE80211_AMPDU_TX_OPERATIONAL:
1694 ista = (struct ath9k_htc_sta *) sta->drv_priv;
1695 ista->tid_state[tid] = AGGR_OPERATIONAL;
1696 break;
1697 default:
1698 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
1699 "Unknown AMPDU action\n");
1700 }
1701
1702 return 0;
1703}
1704
1705static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
1706{
1707 struct ath9k_htc_priv *priv = hw->priv;
1708
1709 mutex_lock(&priv->mutex);
1710 spin_lock_bh(&priv->beacon_lock);
1711 priv->op_flags |= OP_SCANNING;
1712 spin_unlock_bh(&priv->beacon_lock);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301713 cancel_work_sync(&priv->ps_work);
Sujithfb9987d2010-03-17 14:25:25 +05301714 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1715 mutex_unlock(&priv->mutex);
1716}
1717
1718static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
1719{
1720 struct ath9k_htc_priv *priv = hw->priv;
1721
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301722 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301723 mutex_lock(&priv->mutex);
1724 spin_lock_bh(&priv->beacon_lock);
1725 priv->op_flags &= ~OP_SCANNING;
1726 spin_unlock_bh(&priv->beacon_lock);
1727 priv->op_flags |= OP_FULL_RESET;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301728 if (priv->op_flags & OP_ASSOCIATED)
Sujithfcb93922010-04-16 11:53:48 +05301729 ath9k_htc_beacon_config(priv, priv->vif);
Sujithfb9987d2010-03-17 14:25:25 +05301730 ath_start_ani(priv);
1731 mutex_unlock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301732 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301733}
1734
1735static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1736{
1737 return 0;
1738}
1739
1740static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
1741 u8 coverage_class)
1742{
1743 struct ath9k_htc_priv *priv = hw->priv;
1744
1745 mutex_lock(&priv->mutex);
1746 priv->ah->coverage_class = coverage_class;
1747 ath9k_hw_init_global_settings(priv->ah);
1748 mutex_unlock(&priv->mutex);
1749}
1750
1751struct ieee80211_ops ath9k_htc_ops = {
1752 .tx = ath9k_htc_tx,
1753 .start = ath9k_htc_start,
1754 .stop = ath9k_htc_stop,
1755 .add_interface = ath9k_htc_add_interface,
1756 .remove_interface = ath9k_htc_remove_interface,
1757 .config = ath9k_htc_config,
1758 .configure_filter = ath9k_htc_configure_filter,
1759 .sta_notify = ath9k_htc_sta_notify,
1760 .conf_tx = ath9k_htc_conf_tx,
1761 .bss_info_changed = ath9k_htc_bss_info_changed,
1762 .set_key = ath9k_htc_set_key,
1763 .get_tsf = ath9k_htc_get_tsf,
1764 .set_tsf = ath9k_htc_set_tsf,
1765 .reset_tsf = ath9k_htc_reset_tsf,
1766 .ampdu_action = ath9k_htc_ampdu_action,
1767 .sw_scan_start = ath9k_htc_sw_scan_start,
1768 .sw_scan_complete = ath9k_htc_sw_scan_complete,
1769 .set_rts_threshold = ath9k_htc_set_rts_threshold,
1770 .rfkill_poll = ath9k_htc_rfkill_poll_state,
1771 .set_coverage_class = ath9k_htc_set_coverage_class,
1772};