blob: 6bc05fe9be8c876af2207881a7464481b60c528a [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
Sujith881ac6a2010-06-01 15:14:11 +05301055static void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
1056{
1057 struct ath9k_htc_priv *priv = hw->priv;
1058 struct ath_hw *ah = priv->ah;
1059 struct ath_common *common = ath9k_hw_common(ah);
1060 int ret;
1061 u8 cmd_rsp;
1062
1063 if (!ah->curchan)
1064 ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
1065
1066 /* Reset the HW */
1067 ret = ath9k_hw_reset(ah, ah->curchan, false);
1068 if (ret) {
1069 ath_print(common, ATH_DBG_FATAL,
1070 "Unable to reset hardware; reset status %d "
1071 "(freq %u MHz)\n", ret, ah->curchan->channel);
1072 }
1073
1074 ath_update_txpow(priv);
1075
1076 /* Start RX */
1077 WMI_CMD(WMI_START_RECV_CMDID);
1078 ath9k_host_rx_init(priv);
1079
1080 /* Start TX */
1081 htc_start(priv->htc);
1082 spin_lock_bh(&priv->tx_lock);
1083 priv->tx_queues_stop = false;
1084 spin_unlock_bh(&priv->tx_lock);
1085 ieee80211_wake_queues(hw);
1086
1087 WMI_CMD(WMI_ENABLE_INTR_CMDID);
1088
1089 /* Enable LED */
1090 ath9k_hw_cfg_output(ah, ah->led_pin,
1091 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
1092 ath9k_hw_set_gpio(ah, ah->led_pin, 0);
1093}
1094
1095static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
1096{
1097 struct ath9k_htc_priv *priv = hw->priv;
1098 struct ath_hw *ah = priv->ah;
1099 struct ath_common *common = ath9k_hw_common(ah);
1100 int ret;
1101 u8 cmd_rsp;
1102
1103 ath9k_htc_ps_wakeup(priv);
1104
1105 /* Disable LED */
1106 ath9k_hw_set_gpio(ah, ah->led_pin, 1);
1107 ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
1108
1109 WMI_CMD(WMI_DISABLE_INTR_CMDID);
1110
1111 /* Stop TX */
1112 ieee80211_stop_queues(hw);
1113 htc_stop(priv->htc);
1114 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
1115 skb_queue_purge(&priv->tx_queue);
1116
1117 /* Stop RX */
1118 WMI_CMD(WMI_STOP_RECV_CMDID);
1119
Sujith21d51302010-06-01 15:14:18 +05301120 /*
1121 * The MIB counters have to be disabled here,
1122 * since the target doesn't do it.
1123 */
1124 ath9k_hw_disable_mib_counters(ah);
1125
Sujith881ac6a2010-06-01 15:14:11 +05301126 if (!ah->curchan)
1127 ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
1128
1129 /* Reset the HW */
1130 ret = ath9k_hw_reset(ah, ah->curchan, false);
1131 if (ret) {
1132 ath_print(common, ATH_DBG_FATAL,
1133 "Unable to reset hardware; reset status %d "
1134 "(freq %u MHz)\n", ret, ah->curchan->channel);
1135 }
1136
1137 /* Disable the PHY */
1138 ath9k_hw_phy_disable(ah);
1139
1140 ath9k_htc_ps_restore(priv);
1141 ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
1142}
1143
Sujithfb9987d2010-03-17 14:25:25 +05301144/**********************/
1145/* mac80211 Callbacks */
1146/**********************/
1147
1148static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1149{
1150 struct ieee80211_hdr *hdr;
1151 struct ath9k_htc_priv *priv = hw->priv;
Sujith7757dfe2010-03-29 16:07:17 +05301152 int padpos, padsize, ret;
Sujithfb9987d2010-03-17 14:25:25 +05301153
1154 hdr = (struct ieee80211_hdr *) skb->data;
1155
1156 /* Add the padding after the header if this is not already done */
1157 padpos = ath9k_cmn_padpos(hdr->frame_control);
1158 padsize = padpos & 3;
1159 if (padsize && skb->len > padpos) {
1160 if (skb_headroom(skb) < padsize)
1161 return -1;
1162 skb_push(skb, padsize);
1163 memmove(skb->data, skb->data + padsize, padpos);
1164 }
1165
Sujith7757dfe2010-03-29 16:07:17 +05301166 ret = ath9k_htc_tx_start(priv, skb);
1167 if (ret != 0) {
1168 if (ret == -ENOMEM) {
1169 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1170 "Stopping TX queues\n");
1171 ieee80211_stop_queues(hw);
1172 spin_lock_bh(&priv->tx_lock);
1173 priv->tx_queues_stop = true;
1174 spin_unlock_bh(&priv->tx_lock);
1175 } else {
1176 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1177 "Tx failed");
1178 }
Sujithfb9987d2010-03-17 14:25:25 +05301179 goto fail_tx;
1180 }
1181
1182 return 0;
1183
1184fail_tx:
1185 dev_kfree_skb_any(skb);
1186 return 0;
1187}
1188
Sujith881ac6a2010-06-01 15:14:11 +05301189static int ath9k_htc_start(struct ieee80211_hw *hw)
Sujithfb9987d2010-03-17 14:25:25 +05301190{
1191 struct ath9k_htc_priv *priv = hw->priv;
1192 struct ath_hw *ah = priv->ah;
1193 struct ath_common *common = ath9k_hw_common(ah);
1194 struct ieee80211_channel *curchan = hw->conf.channel;
1195 struct ath9k_channel *init_channel;
1196 int ret = 0;
1197 enum htc_phymode mode;
Sujith7f1f5a02010-04-16 11:54:03 +05301198 __be16 htc_mode;
Sujithfb9987d2010-03-17 14:25:25 +05301199 u8 cmd_rsp;
1200
Sujith881ac6a2010-06-01 15:14:11 +05301201 mutex_lock(&priv->mutex);
1202
Sujithfb9987d2010-03-17 14:25:25 +05301203 ath_print(common, ATH_DBG_CONFIG,
1204 "Starting driver with initial channel: %d MHz\n",
1205 curchan->center_freq);
1206
Sujith21d51302010-06-01 15:14:18 +05301207 /* Ensure that HW is awake before flushing RX */
1208 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1209 WMI_CMD(WMI_FLUSH_RECV_CMDID);
1210
Sujithfb9987d2010-03-17 14:25:25 +05301211 /* setup initial channel */
1212 init_channel = ath9k_cmn_get_curchannel(hw, ah);
1213
1214 /* Reset SERDES registers */
1215 ath9k_hw_configpcipowersave(ah, 0, 0);
1216
1217 ath9k_hw_htc_resetinit(ah);
1218 ret = ath9k_hw_reset(ah, init_channel, false);
1219 if (ret) {
1220 ath_print(common, ATH_DBG_FATAL,
1221 "Unable to reset hardware; reset status %d "
1222 "(freq %u MHz)\n", ret, curchan->center_freq);
Sujith881ac6a2010-06-01 15:14:11 +05301223 mutex_unlock(&priv->mutex);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301224 return ret;
Sujithfb9987d2010-03-17 14:25:25 +05301225 }
1226
1227 ath_update_txpow(priv);
1228
1229 mode = ath9k_htc_get_curmode(priv, init_channel);
1230 htc_mode = cpu_to_be16(mode);
1231 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
Sujithfb9987d2010-03-17 14:25:25 +05301232 WMI_CMD(WMI_ATH_INIT_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301233 WMI_CMD(WMI_START_RECV_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301234
1235 ath9k_host_rx_init(priv);
1236
1237 priv->op_flags &= ~OP_INVALID;
1238 htc_start(priv->htc);
1239
Sujith7757dfe2010-03-29 16:07:17 +05301240 spin_lock_bh(&priv->tx_lock);
1241 priv->tx_queues_stop = false;
1242 spin_unlock_bh(&priv->tx_lock);
1243
1244 ieee80211_wake_queues(hw);
1245
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301246 mutex_unlock(&priv->mutex);
1247
1248 return ret;
1249}
1250
Sujith881ac6a2010-06-01 15:14:11 +05301251static void ath9k_htc_stop(struct ieee80211_hw *hw)
Sujithfb9987d2010-03-17 14:25:25 +05301252{
1253 struct ath9k_htc_priv *priv = hw->priv;
1254 struct ath_hw *ah = priv->ah;
1255 struct ath_common *common = ath9k_hw_common(ah);
1256 int ret = 0;
1257 u8 cmd_rsp;
1258
Sujith881ac6a2010-06-01 15:14:11 +05301259 mutex_lock(&priv->mutex);
1260
Sujithfb9987d2010-03-17 14:25:25 +05301261 if (priv->op_flags & OP_INVALID) {
1262 ath_print(common, ATH_DBG_ANY, "Device not present\n");
Sujith881ac6a2010-06-01 15:14:11 +05301263 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301264 return;
1265 }
1266
Sujith7073daa2010-04-23 10:28:13 +05301267 /* Cancel all the running timers/work .. */
1268 cancel_work_sync(&priv->ps_work);
1269 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1270 cancel_delayed_work_sync(&priv->ath9k_aggr_work);
1271 cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
1272 ath9k_led_stop_brightness(priv);
1273
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301274 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301275 htc_stop(priv->htc);
1276 WMI_CMD(WMI_DISABLE_INTR_CMDID);
1277 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
1278 WMI_CMD(WMI_STOP_RECV_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301279 skb_queue_purge(&priv->tx_queue);
1280
1281 /* Remove monitor interface here */
1282 if (ah->opmode == NL80211_IFTYPE_MONITOR) {
1283 if (ath9k_htc_remove_monitor_interface(priv))
1284 ath_print(common, ATH_DBG_FATAL,
1285 "Unable to remove monitor interface\n");
1286 else
1287 ath_print(common, ATH_DBG_CONFIG,
1288 "Monitor interface removed\n");
1289 }
1290
Sujithe9201f02010-06-01 15:14:17 +05301291 ath9k_hw_phy_disable(ah);
1292 ath9k_hw_disable(ah);
1293 ath9k_hw_configpcipowersave(ah, 1, 1);
1294 ath9k_htc_ps_restore(priv);
1295 ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
1296
Sujithfb9987d2010-03-17 14:25:25 +05301297 priv->op_flags |= OP_INVALID;
Sujithfb9987d2010-03-17 14:25:25 +05301298
1299 ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301300 mutex_unlock(&priv->mutex);
1301}
1302
Sujithfb9987d2010-03-17 14:25:25 +05301303static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
1304 struct ieee80211_vif *vif)
1305{
1306 struct ath9k_htc_priv *priv = hw->priv;
1307 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1308 struct ath_common *common = ath9k_hw_common(priv->ah);
1309 struct ath9k_htc_target_vif hvif;
1310 int ret = 0;
1311 u8 cmd_rsp;
1312
1313 mutex_lock(&priv->mutex);
1314
1315 /* Only one interface for now */
1316 if (priv->nvifs > 0) {
1317 ret = -ENOBUFS;
1318 goto out;
1319 }
1320
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301321 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301322 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1323 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1324
1325 switch (vif->type) {
1326 case NL80211_IFTYPE_STATION:
1327 hvif.opmode = cpu_to_be32(HTC_M_STA);
1328 break;
1329 case NL80211_IFTYPE_ADHOC:
1330 hvif.opmode = cpu_to_be32(HTC_M_IBSS);
1331 break;
1332 default:
1333 ath_print(common, ATH_DBG_FATAL,
1334 "Interface type %d not yet supported\n", vif->type);
1335 ret = -EOPNOTSUPP;
1336 goto out;
1337 }
1338
1339 ath_print(common, ATH_DBG_CONFIG,
1340 "Attach a VIF of type: %d\n", vif->type);
1341
1342 priv->ah->opmode = vif->type;
1343
1344 /* Index starts from zero on the target */
1345 avp->index = hvif.index = priv->nvifs;
1346 hvif.rtsthreshold = cpu_to_be16(2304);
1347 WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
1348 if (ret)
1349 goto out;
1350
1351 priv->nvifs++;
1352
1353 /*
1354 * We need a node in target to tx mgmt frames
1355 * before association.
1356 */
1357 ret = ath9k_htc_add_station(priv, vif, NULL);
1358 if (ret)
1359 goto out;
1360
1361 ret = ath9k_htc_update_cap_target(priv);
1362 if (ret)
1363 ath_print(common, ATH_DBG_CONFIG, "Failed to update"
1364 " capability in target \n");
1365
1366 priv->vif = vif;
1367out:
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301368 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301369 mutex_unlock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301370
Sujithfb9987d2010-03-17 14:25:25 +05301371 return ret;
1372}
1373
1374static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
1375 struct ieee80211_vif *vif)
1376{
1377 struct ath9k_htc_priv *priv = hw->priv;
1378 struct ath_common *common = ath9k_hw_common(priv->ah);
1379 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1380 struct ath9k_htc_target_vif hvif;
1381 int ret = 0;
1382 u8 cmd_rsp;
1383
1384 ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
1385
1386 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301387 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301388
1389 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1390 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1391 hvif.index = avp->index;
1392 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
1393 priv->nvifs--;
1394
1395 ath9k_htc_remove_station(priv, vif, NULL);
Sujithfb9987d2010-03-17 14:25:25 +05301396 priv->vif = NULL;
1397
Sujithcb551df2010-06-01 15:14:12 +05301398 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301399 mutex_unlock(&priv->mutex);
1400}
1401
1402static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
1403{
1404 struct ath9k_htc_priv *priv = hw->priv;
1405 struct ath_common *common = ath9k_hw_common(priv->ah);
1406 struct ieee80211_conf *conf = &hw->conf;
1407
1408 mutex_lock(&priv->mutex);
1409
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301410 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1411 bool enable_radio = false;
1412 bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
1413
Sujith23367762010-06-01 15:14:16 +05301414 mutex_lock(&priv->htc_pm_lock);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301415 if (!idle && priv->ps_idle)
1416 enable_radio = true;
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301417 priv->ps_idle = idle;
Sujith23367762010-06-01 15:14:16 +05301418 mutex_unlock(&priv->htc_pm_lock);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301419
1420 if (enable_radio) {
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301421 ath_print(common, ATH_DBG_CONFIG,
1422 "not-idle: enabling radio\n");
Sujith23367762010-06-01 15:14:16 +05301423 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1424 ath9k_htc_radio_enable(hw);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301425 }
1426 }
1427
Sujithfb9987d2010-03-17 14:25:25 +05301428 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1429 struct ieee80211_channel *curchan = hw->conf.channel;
1430 int pos = curchan->hw_value;
Sujithfb9987d2010-03-17 14:25:25 +05301431
1432 ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
1433 curchan->center_freq);
1434
Sujithfb9987d2010-03-17 14:25:25 +05301435 ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
1436
1437 if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
1438 ath_print(common, ATH_DBG_FATAL,
1439 "Unable to set channel\n");
1440 mutex_unlock(&priv->mutex);
1441 return -EINVAL;
1442 }
1443
1444 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301445 if (changed & IEEE80211_CONF_CHANGE_PS) {
1446 if (conf->flags & IEEE80211_CONF_PS) {
1447 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
1448 priv->ps_enabled = true;
1449 } else {
1450 priv->ps_enabled = false;
1451 cancel_work_sync(&priv->ps_work);
1452 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1453 }
1454 }
Sujithfb9987d2010-03-17 14:25:25 +05301455
1456 if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
1457 if (conf->flags & IEEE80211_CONF_MONITOR) {
1458 if (ath9k_htc_add_monitor_interface(priv))
1459 ath_print(common, ATH_DBG_FATAL,
1460 "Failed to set monitor mode\n");
1461 else
1462 ath_print(common, ATH_DBG_CONFIG,
1463 "HW opmode set to Monitor mode\n");
1464 }
1465 }
1466
Sujith23367762010-06-01 15:14:16 +05301467 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1468 mutex_lock(&priv->htc_pm_lock);
1469 if (!priv->ps_idle) {
1470 mutex_unlock(&priv->htc_pm_lock);
1471 goto out;
1472 }
1473 mutex_unlock(&priv->htc_pm_lock);
1474
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301475 ath_print(common, ATH_DBG_CONFIG,
1476 "idle: disabling radio\n");
Sujith881ac6a2010-06-01 15:14:11 +05301477 ath9k_htc_radio_disable(hw);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301478 }
1479
Sujith23367762010-06-01 15:14:16 +05301480out:
Sujithfb9987d2010-03-17 14:25:25 +05301481 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301482 return 0;
1483}
1484
1485#define SUPPORTED_FILTERS \
1486 (FIF_PROMISC_IN_BSS | \
1487 FIF_ALLMULTI | \
1488 FIF_CONTROL | \
1489 FIF_PSPOLL | \
1490 FIF_OTHER_BSS | \
1491 FIF_BCN_PRBRESP_PROMISC | \
1492 FIF_FCSFAIL)
1493
1494static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
1495 unsigned int changed_flags,
1496 unsigned int *total_flags,
1497 u64 multicast)
1498{
1499 struct ath9k_htc_priv *priv = hw->priv;
1500 u32 rfilt;
1501
1502 mutex_lock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301503 ath9k_htc_ps_wakeup(priv);
Sujithcb551df2010-06-01 15:14:12 +05301504
Sujithfb9987d2010-03-17 14:25:25 +05301505 changed_flags &= SUPPORTED_FILTERS;
1506 *total_flags &= SUPPORTED_FILTERS;
1507
1508 priv->rxfilter = *total_flags;
Sujith0995d112010-03-29 16:07:09 +05301509 rfilt = ath9k_htc_calcrxfilter(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301510 ath9k_hw_setrxfilter(priv->ah, rfilt);
1511
1512 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
1513 "Set HW RX filter: 0x%x\n", rfilt);
1514
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301515 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301516 mutex_unlock(&priv->mutex);
1517}
1518
1519static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
1520 struct ieee80211_vif *vif,
1521 enum sta_notify_cmd cmd,
1522 struct ieee80211_sta *sta)
1523{
1524 struct ath9k_htc_priv *priv = hw->priv;
1525 int ret;
1526
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301527 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301528 ath9k_htc_ps_wakeup(priv);
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301529
Sujithfb9987d2010-03-17 14:25:25 +05301530 switch (cmd) {
1531 case STA_NOTIFY_ADD:
1532 ret = ath9k_htc_add_station(priv, vif, sta);
1533 if (!ret)
Sujith0d425a72010-05-17 12:01:16 +05301534 ath9k_htc_init_rate(priv, sta);
Sujithfb9987d2010-03-17 14:25:25 +05301535 break;
1536 case STA_NOTIFY_REMOVE:
1537 ath9k_htc_remove_station(priv, vif, sta);
1538 break;
1539 default:
1540 break;
1541 }
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301542
Sujithcb551df2010-06-01 15:14:12 +05301543 ath9k_htc_ps_restore(priv);
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301544 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301545}
1546
1547static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
1548 const struct ieee80211_tx_queue_params *params)
1549{
1550 struct ath9k_htc_priv *priv = hw->priv;
1551 struct ath_common *common = ath9k_hw_common(priv->ah);
1552 struct ath9k_tx_queue_info qi;
1553 int ret = 0, qnum;
1554
1555 if (queue >= WME_NUM_AC)
1556 return 0;
1557
1558 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301559 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301560
1561 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
1562
1563 qi.tqi_aifs = params->aifs;
1564 qi.tqi_cwmin = params->cw_min;
1565 qi.tqi_cwmax = params->cw_max;
1566 qi.tqi_burstTime = params->txop;
1567
1568 qnum = get_hw_qnum(queue, priv->hwq_map);
1569
1570 ath_print(common, ATH_DBG_CONFIG,
1571 "Configure tx [queue/hwq] [%d/%d], "
1572 "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
1573 queue, qnum, params->aifs, params->cw_min,
1574 params->cw_max, params->txop);
1575
Sujithe1572c52010-03-24 13:42:13 +05301576 ret = ath_htc_txq_update(priv, qnum, &qi);
Sujithfb9987d2010-03-17 14:25:25 +05301577 if (ret)
1578 ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
1579
Sujithcb551df2010-06-01 15:14:12 +05301580 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301581 mutex_unlock(&priv->mutex);
1582
1583 return ret;
1584}
1585
1586static int ath9k_htc_set_key(struct ieee80211_hw *hw,
1587 enum set_key_cmd cmd,
1588 struct ieee80211_vif *vif,
1589 struct ieee80211_sta *sta,
1590 struct ieee80211_key_conf *key)
1591{
1592 struct ath9k_htc_priv *priv = hw->priv;
1593 struct ath_common *common = ath9k_hw_common(priv->ah);
1594 int ret = 0;
1595
Sujithe1572c52010-03-24 13:42:13 +05301596 if (htc_modparam_nohwcrypt)
Sujithfb9987d2010-03-17 14:25:25 +05301597 return -ENOSPC;
1598
1599 mutex_lock(&priv->mutex);
1600 ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301601 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301602
1603 switch (cmd) {
1604 case SET_KEY:
1605 ret = ath9k_cmn_key_config(common, vif, sta, key);
1606 if (ret >= 0) {
1607 key->hw_key_idx = ret;
1608 /* push IV and Michael MIC generation to stack */
1609 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
1610 if (key->alg == ALG_TKIP)
1611 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
1612 if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
1613 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
1614 ret = 0;
1615 }
1616 break;
1617 case DISABLE_KEY:
1618 ath9k_cmn_key_delete(common, key);
1619 break;
1620 default:
1621 ret = -EINVAL;
1622 }
1623
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301624 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301625 mutex_unlock(&priv->mutex);
1626
1627 return ret;
1628}
1629
1630static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
1631 struct ieee80211_vif *vif,
1632 struct ieee80211_bss_conf *bss_conf,
1633 u32 changed)
1634{
1635 struct ath9k_htc_priv *priv = hw->priv;
1636 struct ath_hw *ah = priv->ah;
1637 struct ath_common *common = ath9k_hw_common(ah);
1638
1639 mutex_lock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301640 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301641
1642 if (changed & BSS_CHANGED_ASSOC) {
1643 common->curaid = bss_conf->assoc ?
1644 bss_conf->aid : 0;
1645 ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
1646 bss_conf->assoc);
1647
1648 if (bss_conf->assoc) {
1649 priv->op_flags |= OP_ASSOCIATED;
1650 ath_start_ani(priv);
1651 } else {
1652 priv->op_flags &= ~OP_ASSOCIATED;
1653 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1654 }
1655 }
1656
1657 if (changed & BSS_CHANGED_BSSID) {
1658 /* Set BSSID */
1659 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1660 ath9k_hw_write_associd(ah);
1661
1662 ath_print(common, ATH_DBG_CONFIG,
1663 "BSSID: %pM aid: 0x%x\n",
1664 common->curbssid, common->curaid);
1665 }
1666
1667 if ((changed & BSS_CHANGED_BEACON_INT) ||
1668 (changed & BSS_CHANGED_BEACON) ||
1669 ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1670 bss_conf->enable_beacon)) {
1671 priv->op_flags |= OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301672 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301673 }
1674
Sujithfb9987d2010-03-17 14:25:25 +05301675 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1676 !bss_conf->enable_beacon) {
1677 priv->op_flags &= ~OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301678 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301679 }
1680
1681 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1682 ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
1683 bss_conf->use_short_preamble);
1684 if (bss_conf->use_short_preamble)
1685 priv->op_flags |= OP_PREAMBLE_SHORT;
1686 else
1687 priv->op_flags &= ~OP_PREAMBLE_SHORT;
1688 }
1689
1690 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1691 ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
1692 bss_conf->use_cts_prot);
1693 if (bss_conf->use_cts_prot &&
1694 hw->conf.channel->band != IEEE80211_BAND_5GHZ)
1695 priv->op_flags |= OP_PROTECT_ENABLE;
1696 else
1697 priv->op_flags &= ~OP_PROTECT_ENABLE;
1698 }
1699
1700 if (changed & BSS_CHANGED_ERP_SLOT) {
1701 if (bss_conf->use_short_slot)
1702 ah->slottime = 9;
1703 else
1704 ah->slottime = 20;
1705
1706 ath9k_hw_init_global_settings(ah);
1707 }
1708
Sujith2c76ef82010-05-17 12:01:18 +05301709 if (changed & BSS_CHANGED_HT)
1710 ath9k_htc_update_rate(priv, vif, bss_conf);
1711
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301712 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301713 mutex_unlock(&priv->mutex);
1714}
1715
1716static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
1717{
1718 struct ath9k_htc_priv *priv = hw->priv;
1719 u64 tsf;
1720
1721 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301722 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301723 tsf = ath9k_hw_gettsf64(priv->ah);
Sujithcb551df2010-06-01 15:14:12 +05301724 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301725 mutex_unlock(&priv->mutex);
1726
1727 return tsf;
1728}
1729
1730static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
1731{
1732 struct ath9k_htc_priv *priv = hw->priv;
1733
1734 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301735 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301736 ath9k_hw_settsf64(priv->ah, tsf);
Sujithcb551df2010-06-01 15:14:12 +05301737 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301738 mutex_unlock(&priv->mutex);
1739}
1740
1741static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
1742{
1743 struct ath9k_htc_priv *priv = hw->priv;
1744
1745 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301746 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301747 ath9k_hw_reset_tsf(priv->ah);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301748 ath9k_htc_ps_restore(priv);
Sujithcb551df2010-06-01 15:14:12 +05301749 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301750}
1751
1752static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
1753 struct ieee80211_vif *vif,
1754 enum ieee80211_ampdu_mlme_action action,
1755 struct ieee80211_sta *sta,
1756 u16 tid, u16 *ssn)
1757{
1758 struct ath9k_htc_priv *priv = hw->priv;
1759 struct ath9k_htc_aggr_work *work = &priv->aggr_work;
1760 struct ath9k_htc_sta *ista;
1761
1762 switch (action) {
1763 case IEEE80211_AMPDU_RX_START:
1764 break;
1765 case IEEE80211_AMPDU_RX_STOP:
1766 break;
1767 case IEEE80211_AMPDU_TX_START:
1768 case IEEE80211_AMPDU_TX_STOP:
1769 if (!(priv->op_flags & OP_TXAGGR))
1770 return -ENOTSUPP;
1771 memcpy(work->sta_addr, sta->addr, ETH_ALEN);
1772 work->hw = hw;
1773 work->vif = vif;
1774 work->action = action;
1775 work->tid = tid;
1776 ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0);
1777 break;
1778 case IEEE80211_AMPDU_TX_OPERATIONAL:
1779 ista = (struct ath9k_htc_sta *) sta->drv_priv;
1780 ista->tid_state[tid] = AGGR_OPERATIONAL;
1781 break;
1782 default:
1783 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
1784 "Unknown AMPDU action\n");
1785 }
1786
1787 return 0;
1788}
1789
1790static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
1791{
1792 struct ath9k_htc_priv *priv = hw->priv;
1793
1794 mutex_lock(&priv->mutex);
1795 spin_lock_bh(&priv->beacon_lock);
1796 priv->op_flags |= OP_SCANNING;
1797 spin_unlock_bh(&priv->beacon_lock);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301798 cancel_work_sync(&priv->ps_work);
Sujithfb9987d2010-03-17 14:25:25 +05301799 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1800 mutex_unlock(&priv->mutex);
1801}
1802
1803static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
1804{
1805 struct ath9k_htc_priv *priv = hw->priv;
1806
1807 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301808 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301809 spin_lock_bh(&priv->beacon_lock);
1810 priv->op_flags &= ~OP_SCANNING;
1811 spin_unlock_bh(&priv->beacon_lock);
1812 priv->op_flags |= OP_FULL_RESET;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301813 if (priv->op_flags & OP_ASSOCIATED)
Sujithfcb93922010-04-16 11:53:48 +05301814 ath9k_htc_beacon_config(priv, priv->vif);
Sujithfb9987d2010-03-17 14:25:25 +05301815 ath_start_ani(priv);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301816 ath9k_htc_ps_restore(priv);
Sujithcb551df2010-06-01 15:14:12 +05301817 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301818}
1819
1820static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1821{
1822 return 0;
1823}
1824
1825static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
1826 u8 coverage_class)
1827{
1828 struct ath9k_htc_priv *priv = hw->priv;
1829
1830 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301831 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301832 priv->ah->coverage_class = coverage_class;
1833 ath9k_hw_init_global_settings(priv->ah);
Sujithcb551df2010-06-01 15:14:12 +05301834 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301835 mutex_unlock(&priv->mutex);
1836}
1837
1838struct ieee80211_ops ath9k_htc_ops = {
1839 .tx = ath9k_htc_tx,
1840 .start = ath9k_htc_start,
1841 .stop = ath9k_htc_stop,
1842 .add_interface = ath9k_htc_add_interface,
1843 .remove_interface = ath9k_htc_remove_interface,
1844 .config = ath9k_htc_config,
1845 .configure_filter = ath9k_htc_configure_filter,
1846 .sta_notify = ath9k_htc_sta_notify,
1847 .conf_tx = ath9k_htc_conf_tx,
1848 .bss_info_changed = ath9k_htc_bss_info_changed,
1849 .set_key = ath9k_htc_set_key,
1850 .get_tsf = ath9k_htc_get_tsf,
1851 .set_tsf = ath9k_htc_set_tsf,
1852 .reset_tsf = ath9k_htc_reset_tsf,
1853 .ampdu_action = ath9k_htc_ampdu_action,
1854 .sw_scan_start = ath9k_htc_sw_scan_start,
1855 .sw_scan_complete = ath9k_htc_sw_scan_complete,
1856 .set_rts_threshold = ath9k_htc_set_rts_threshold,
1857 .rfkill_poll = ath9k_htc_rfkill_poll_state,
1858 .set_coverage_class = ath9k_htc_set_coverage_class,
1859};