blob: b62bfa57dd42c1741c1f2ac14e39b285f0ff28cc [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
1120 if (!ah->curchan)
1121 ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
1122
1123 /* Reset the HW */
1124 ret = ath9k_hw_reset(ah, ah->curchan, false);
1125 if (ret) {
1126 ath_print(common, ATH_DBG_FATAL,
1127 "Unable to reset hardware; reset status %d "
1128 "(freq %u MHz)\n", ret, ah->curchan->channel);
1129 }
1130
1131 /* Disable the PHY */
1132 ath9k_hw_phy_disable(ah);
1133
1134 ath9k_htc_ps_restore(priv);
1135 ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
1136}
1137
Sujithfb9987d2010-03-17 14:25:25 +05301138/**********************/
1139/* mac80211 Callbacks */
1140/**********************/
1141
1142static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1143{
1144 struct ieee80211_hdr *hdr;
1145 struct ath9k_htc_priv *priv = hw->priv;
Sujith7757dfe2010-03-29 16:07:17 +05301146 int padpos, padsize, ret;
Sujithfb9987d2010-03-17 14:25:25 +05301147
1148 hdr = (struct ieee80211_hdr *) skb->data;
1149
1150 /* Add the padding after the header if this is not already done */
1151 padpos = ath9k_cmn_padpos(hdr->frame_control);
1152 padsize = padpos & 3;
1153 if (padsize && skb->len > padpos) {
1154 if (skb_headroom(skb) < padsize)
1155 return -1;
1156 skb_push(skb, padsize);
1157 memmove(skb->data, skb->data + padsize, padpos);
1158 }
1159
Sujith7757dfe2010-03-29 16:07:17 +05301160 ret = ath9k_htc_tx_start(priv, skb);
1161 if (ret != 0) {
1162 if (ret == -ENOMEM) {
1163 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1164 "Stopping TX queues\n");
1165 ieee80211_stop_queues(hw);
1166 spin_lock_bh(&priv->tx_lock);
1167 priv->tx_queues_stop = true;
1168 spin_unlock_bh(&priv->tx_lock);
1169 } else {
1170 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1171 "Tx failed");
1172 }
Sujithfb9987d2010-03-17 14:25:25 +05301173 goto fail_tx;
1174 }
1175
1176 return 0;
1177
1178fail_tx:
1179 dev_kfree_skb_any(skb);
1180 return 0;
1181}
1182
Sujith881ac6a2010-06-01 15:14:11 +05301183static int ath9k_htc_start(struct ieee80211_hw *hw)
Sujithfb9987d2010-03-17 14:25:25 +05301184{
1185 struct ath9k_htc_priv *priv = hw->priv;
1186 struct ath_hw *ah = priv->ah;
1187 struct ath_common *common = ath9k_hw_common(ah);
1188 struct ieee80211_channel *curchan = hw->conf.channel;
1189 struct ath9k_channel *init_channel;
1190 int ret = 0;
1191 enum htc_phymode mode;
Sujith7f1f5a02010-04-16 11:54:03 +05301192 __be16 htc_mode;
Sujithfb9987d2010-03-17 14:25:25 +05301193 u8 cmd_rsp;
1194
Sujith881ac6a2010-06-01 15:14:11 +05301195 mutex_lock(&priv->mutex);
1196
Sujithfb9987d2010-03-17 14:25:25 +05301197 ath_print(common, ATH_DBG_CONFIG,
1198 "Starting driver with initial channel: %d MHz\n",
1199 curchan->center_freq);
1200
Sujithfb9987d2010-03-17 14:25:25 +05301201 /* setup initial channel */
1202 init_channel = ath9k_cmn_get_curchannel(hw, ah);
1203
1204 /* Reset SERDES registers */
1205 ath9k_hw_configpcipowersave(ah, 0, 0);
1206
1207 ath9k_hw_htc_resetinit(ah);
1208 ret = ath9k_hw_reset(ah, init_channel, false);
1209 if (ret) {
1210 ath_print(common, ATH_DBG_FATAL,
1211 "Unable to reset hardware; reset status %d "
1212 "(freq %u MHz)\n", ret, curchan->center_freq);
Sujith881ac6a2010-06-01 15:14:11 +05301213 mutex_unlock(&priv->mutex);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301214 return ret;
Sujithfb9987d2010-03-17 14:25:25 +05301215 }
1216
1217 ath_update_txpow(priv);
1218
1219 mode = ath9k_htc_get_curmode(priv, init_channel);
1220 htc_mode = cpu_to_be16(mode);
1221 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
Sujithfb9987d2010-03-17 14:25:25 +05301222 WMI_CMD(WMI_ATH_INIT_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301223 WMI_CMD(WMI_START_RECV_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301224
1225 ath9k_host_rx_init(priv);
1226
1227 priv->op_flags &= ~OP_INVALID;
1228 htc_start(priv->htc);
1229
Sujith7757dfe2010-03-29 16:07:17 +05301230 spin_lock_bh(&priv->tx_lock);
1231 priv->tx_queues_stop = false;
1232 spin_unlock_bh(&priv->tx_lock);
1233
1234 ieee80211_wake_queues(hw);
1235
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301236 mutex_unlock(&priv->mutex);
1237
1238 return ret;
1239}
1240
Sujith881ac6a2010-06-01 15:14:11 +05301241static void ath9k_htc_stop(struct ieee80211_hw *hw)
Sujithfb9987d2010-03-17 14:25:25 +05301242{
1243 struct ath9k_htc_priv *priv = hw->priv;
1244 struct ath_hw *ah = priv->ah;
1245 struct ath_common *common = ath9k_hw_common(ah);
1246 int ret = 0;
1247 u8 cmd_rsp;
1248
Sujith881ac6a2010-06-01 15:14:11 +05301249 mutex_lock(&priv->mutex);
1250
Sujithfb9987d2010-03-17 14:25:25 +05301251 if (priv->op_flags & OP_INVALID) {
1252 ath_print(common, ATH_DBG_ANY, "Device not present\n");
Sujith881ac6a2010-06-01 15:14:11 +05301253 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301254 return;
1255 }
1256
Sujith7073daa2010-04-23 10:28:13 +05301257 /* Cancel all the running timers/work .. */
1258 cancel_work_sync(&priv->ps_work);
1259 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1260 cancel_delayed_work_sync(&priv->ath9k_aggr_work);
1261 cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
1262 ath9k_led_stop_brightness(priv);
1263
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301264 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301265 htc_stop(priv->htc);
1266 WMI_CMD(WMI_DISABLE_INTR_CMDID);
1267 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
1268 WMI_CMD(WMI_STOP_RECV_CMDID);
1269 ath9k_hw_phy_disable(ah);
1270 ath9k_hw_disable(ah);
1271 ath9k_hw_configpcipowersave(ah, 1, 1);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301272 ath9k_htc_ps_restore(priv);
1273 ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
Sujithfb9987d2010-03-17 14:25:25 +05301274
Sujithfb9987d2010-03-17 14:25:25 +05301275 skb_queue_purge(&priv->tx_queue);
1276
1277 /* Remove monitor interface here */
1278 if (ah->opmode == NL80211_IFTYPE_MONITOR) {
1279 if (ath9k_htc_remove_monitor_interface(priv))
1280 ath_print(common, ATH_DBG_FATAL,
1281 "Unable to remove monitor interface\n");
1282 else
1283 ath_print(common, ATH_DBG_CONFIG,
1284 "Monitor interface removed\n");
1285 }
1286
1287 priv->op_flags |= OP_INVALID;
Sujithfb9987d2010-03-17 14:25:25 +05301288
1289 ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301290 mutex_unlock(&priv->mutex);
1291}
1292
Sujithfb9987d2010-03-17 14:25:25 +05301293static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
1294 struct ieee80211_vif *vif)
1295{
1296 struct ath9k_htc_priv *priv = hw->priv;
1297 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1298 struct ath_common *common = ath9k_hw_common(priv->ah);
1299 struct ath9k_htc_target_vif hvif;
1300 int ret = 0;
1301 u8 cmd_rsp;
1302
1303 mutex_lock(&priv->mutex);
1304
1305 /* Only one interface for now */
1306 if (priv->nvifs > 0) {
1307 ret = -ENOBUFS;
1308 goto out;
1309 }
1310
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301311 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301312 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1313 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1314
1315 switch (vif->type) {
1316 case NL80211_IFTYPE_STATION:
1317 hvif.opmode = cpu_to_be32(HTC_M_STA);
1318 break;
1319 case NL80211_IFTYPE_ADHOC:
1320 hvif.opmode = cpu_to_be32(HTC_M_IBSS);
1321 break;
1322 default:
1323 ath_print(common, ATH_DBG_FATAL,
1324 "Interface type %d not yet supported\n", vif->type);
1325 ret = -EOPNOTSUPP;
1326 goto out;
1327 }
1328
1329 ath_print(common, ATH_DBG_CONFIG,
1330 "Attach a VIF of type: %d\n", vif->type);
1331
1332 priv->ah->opmode = vif->type;
1333
1334 /* Index starts from zero on the target */
1335 avp->index = hvif.index = priv->nvifs;
1336 hvif.rtsthreshold = cpu_to_be16(2304);
1337 WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
1338 if (ret)
1339 goto out;
1340
1341 priv->nvifs++;
1342
1343 /*
1344 * We need a node in target to tx mgmt frames
1345 * before association.
1346 */
1347 ret = ath9k_htc_add_station(priv, vif, NULL);
1348 if (ret)
1349 goto out;
1350
1351 ret = ath9k_htc_update_cap_target(priv);
1352 if (ret)
1353 ath_print(common, ATH_DBG_CONFIG, "Failed to update"
1354 " capability in target \n");
1355
1356 priv->vif = vif;
1357out:
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301358 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301359 mutex_unlock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301360
Sujithfb9987d2010-03-17 14:25:25 +05301361 return ret;
1362}
1363
1364static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
1365 struct ieee80211_vif *vif)
1366{
1367 struct ath9k_htc_priv *priv = hw->priv;
1368 struct ath_common *common = ath9k_hw_common(priv->ah);
1369 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1370 struct ath9k_htc_target_vif hvif;
1371 int ret = 0;
1372 u8 cmd_rsp;
1373
1374 ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
1375
1376 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301377 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301378
1379 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1380 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1381 hvif.index = avp->index;
1382 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
1383 priv->nvifs--;
1384
1385 ath9k_htc_remove_station(priv, vif, NULL);
Sujithfb9987d2010-03-17 14:25:25 +05301386 priv->vif = NULL;
1387
Sujithcb551df2010-06-01 15:14:12 +05301388 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301389 mutex_unlock(&priv->mutex);
1390}
1391
1392static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
1393{
1394 struct ath9k_htc_priv *priv = hw->priv;
1395 struct ath_common *common = ath9k_hw_common(priv->ah);
1396 struct ieee80211_conf *conf = &hw->conf;
1397
1398 mutex_lock(&priv->mutex);
1399
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301400 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1401 bool enable_radio = false;
1402 bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
1403
Sujith23367762010-06-01 15:14:16 +05301404 mutex_lock(&priv->htc_pm_lock);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301405 if (!idle && priv->ps_idle)
1406 enable_radio = true;
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301407 priv->ps_idle = idle;
Sujith23367762010-06-01 15:14:16 +05301408 mutex_unlock(&priv->htc_pm_lock);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301409
1410 if (enable_radio) {
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301411 ath_print(common, ATH_DBG_CONFIG,
1412 "not-idle: enabling radio\n");
Sujith23367762010-06-01 15:14:16 +05301413 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1414 ath9k_htc_radio_enable(hw);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301415 }
1416 }
1417
Sujithfb9987d2010-03-17 14:25:25 +05301418 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1419 struct ieee80211_channel *curchan = hw->conf.channel;
1420 int pos = curchan->hw_value;
Sujithfb9987d2010-03-17 14:25:25 +05301421
1422 ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
1423 curchan->center_freq);
1424
Sujithfb9987d2010-03-17 14:25:25 +05301425 ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
1426
1427 if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
1428 ath_print(common, ATH_DBG_FATAL,
1429 "Unable to set channel\n");
1430 mutex_unlock(&priv->mutex);
1431 return -EINVAL;
1432 }
1433
1434 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301435 if (changed & IEEE80211_CONF_CHANGE_PS) {
1436 if (conf->flags & IEEE80211_CONF_PS) {
1437 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
1438 priv->ps_enabled = true;
1439 } else {
1440 priv->ps_enabled = false;
1441 cancel_work_sync(&priv->ps_work);
1442 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1443 }
1444 }
Sujithfb9987d2010-03-17 14:25:25 +05301445
1446 if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
1447 if (conf->flags & IEEE80211_CONF_MONITOR) {
1448 if (ath9k_htc_add_monitor_interface(priv))
1449 ath_print(common, ATH_DBG_FATAL,
1450 "Failed to set monitor mode\n");
1451 else
1452 ath_print(common, ATH_DBG_CONFIG,
1453 "HW opmode set to Monitor mode\n");
1454 }
1455 }
1456
Sujith23367762010-06-01 15:14:16 +05301457 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1458 mutex_lock(&priv->htc_pm_lock);
1459 if (!priv->ps_idle) {
1460 mutex_unlock(&priv->htc_pm_lock);
1461 goto out;
1462 }
1463 mutex_unlock(&priv->htc_pm_lock);
1464
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301465 ath_print(common, ATH_DBG_CONFIG,
1466 "idle: disabling radio\n");
Sujith881ac6a2010-06-01 15:14:11 +05301467 ath9k_htc_radio_disable(hw);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301468 }
1469
Sujith23367762010-06-01 15:14:16 +05301470out:
Sujithfb9987d2010-03-17 14:25:25 +05301471 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301472 return 0;
1473}
1474
1475#define SUPPORTED_FILTERS \
1476 (FIF_PROMISC_IN_BSS | \
1477 FIF_ALLMULTI | \
1478 FIF_CONTROL | \
1479 FIF_PSPOLL | \
1480 FIF_OTHER_BSS | \
1481 FIF_BCN_PRBRESP_PROMISC | \
1482 FIF_FCSFAIL)
1483
1484static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
1485 unsigned int changed_flags,
1486 unsigned int *total_flags,
1487 u64 multicast)
1488{
1489 struct ath9k_htc_priv *priv = hw->priv;
1490 u32 rfilt;
1491
1492 mutex_lock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301493 ath9k_htc_ps_wakeup(priv);
Sujithcb551df2010-06-01 15:14:12 +05301494
Sujithfb9987d2010-03-17 14:25:25 +05301495 changed_flags &= SUPPORTED_FILTERS;
1496 *total_flags &= SUPPORTED_FILTERS;
1497
1498 priv->rxfilter = *total_flags;
Sujith0995d112010-03-29 16:07:09 +05301499 rfilt = ath9k_htc_calcrxfilter(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301500 ath9k_hw_setrxfilter(priv->ah, rfilt);
1501
1502 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
1503 "Set HW RX filter: 0x%x\n", rfilt);
1504
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301505 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301506 mutex_unlock(&priv->mutex);
1507}
1508
1509static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
1510 struct ieee80211_vif *vif,
1511 enum sta_notify_cmd cmd,
1512 struct ieee80211_sta *sta)
1513{
1514 struct ath9k_htc_priv *priv = hw->priv;
1515 int ret;
1516
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301517 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301518 ath9k_htc_ps_wakeup(priv);
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301519
Sujithfb9987d2010-03-17 14:25:25 +05301520 switch (cmd) {
1521 case STA_NOTIFY_ADD:
1522 ret = ath9k_htc_add_station(priv, vif, sta);
1523 if (!ret)
Sujith0d425a72010-05-17 12:01:16 +05301524 ath9k_htc_init_rate(priv, sta);
Sujithfb9987d2010-03-17 14:25:25 +05301525 break;
1526 case STA_NOTIFY_REMOVE:
1527 ath9k_htc_remove_station(priv, vif, sta);
1528 break;
1529 default:
1530 break;
1531 }
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301532
Sujithcb551df2010-06-01 15:14:12 +05301533 ath9k_htc_ps_restore(priv);
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301534 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301535}
1536
1537static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
1538 const struct ieee80211_tx_queue_params *params)
1539{
1540 struct ath9k_htc_priv *priv = hw->priv;
1541 struct ath_common *common = ath9k_hw_common(priv->ah);
1542 struct ath9k_tx_queue_info qi;
1543 int ret = 0, qnum;
1544
1545 if (queue >= WME_NUM_AC)
1546 return 0;
1547
1548 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301549 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301550
1551 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
1552
1553 qi.tqi_aifs = params->aifs;
1554 qi.tqi_cwmin = params->cw_min;
1555 qi.tqi_cwmax = params->cw_max;
1556 qi.tqi_burstTime = params->txop;
1557
1558 qnum = get_hw_qnum(queue, priv->hwq_map);
1559
1560 ath_print(common, ATH_DBG_CONFIG,
1561 "Configure tx [queue/hwq] [%d/%d], "
1562 "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
1563 queue, qnum, params->aifs, params->cw_min,
1564 params->cw_max, params->txop);
1565
Sujithe1572c52010-03-24 13:42:13 +05301566 ret = ath_htc_txq_update(priv, qnum, &qi);
Sujithfb9987d2010-03-17 14:25:25 +05301567 if (ret)
1568 ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
1569
Sujithcb551df2010-06-01 15:14:12 +05301570 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301571 mutex_unlock(&priv->mutex);
1572
1573 return ret;
1574}
1575
1576static int ath9k_htc_set_key(struct ieee80211_hw *hw,
1577 enum set_key_cmd cmd,
1578 struct ieee80211_vif *vif,
1579 struct ieee80211_sta *sta,
1580 struct ieee80211_key_conf *key)
1581{
1582 struct ath9k_htc_priv *priv = hw->priv;
1583 struct ath_common *common = ath9k_hw_common(priv->ah);
1584 int ret = 0;
1585
Sujithe1572c52010-03-24 13:42:13 +05301586 if (htc_modparam_nohwcrypt)
Sujithfb9987d2010-03-17 14:25:25 +05301587 return -ENOSPC;
1588
1589 mutex_lock(&priv->mutex);
1590 ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301591 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301592
1593 switch (cmd) {
1594 case SET_KEY:
1595 ret = ath9k_cmn_key_config(common, vif, sta, key);
1596 if (ret >= 0) {
1597 key->hw_key_idx = ret;
1598 /* push IV and Michael MIC generation to stack */
1599 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
1600 if (key->alg == ALG_TKIP)
1601 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
1602 if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
1603 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
1604 ret = 0;
1605 }
1606 break;
1607 case DISABLE_KEY:
1608 ath9k_cmn_key_delete(common, key);
1609 break;
1610 default:
1611 ret = -EINVAL;
1612 }
1613
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301614 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301615 mutex_unlock(&priv->mutex);
1616
1617 return ret;
1618}
1619
1620static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
1621 struct ieee80211_vif *vif,
1622 struct ieee80211_bss_conf *bss_conf,
1623 u32 changed)
1624{
1625 struct ath9k_htc_priv *priv = hw->priv;
1626 struct ath_hw *ah = priv->ah;
1627 struct ath_common *common = ath9k_hw_common(ah);
1628
1629 mutex_lock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301630 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301631
1632 if (changed & BSS_CHANGED_ASSOC) {
1633 common->curaid = bss_conf->assoc ?
1634 bss_conf->aid : 0;
1635 ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
1636 bss_conf->assoc);
1637
1638 if (bss_conf->assoc) {
1639 priv->op_flags |= OP_ASSOCIATED;
1640 ath_start_ani(priv);
1641 } else {
1642 priv->op_flags &= ~OP_ASSOCIATED;
1643 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1644 }
1645 }
1646
1647 if (changed & BSS_CHANGED_BSSID) {
1648 /* Set BSSID */
1649 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1650 ath9k_hw_write_associd(ah);
1651
1652 ath_print(common, ATH_DBG_CONFIG,
1653 "BSSID: %pM aid: 0x%x\n",
1654 common->curbssid, common->curaid);
1655 }
1656
1657 if ((changed & BSS_CHANGED_BEACON_INT) ||
1658 (changed & BSS_CHANGED_BEACON) ||
1659 ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1660 bss_conf->enable_beacon)) {
1661 priv->op_flags |= OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301662 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301663 }
1664
Sujithfb9987d2010-03-17 14:25:25 +05301665 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1666 !bss_conf->enable_beacon) {
1667 priv->op_flags &= ~OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301668 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301669 }
1670
1671 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1672 ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
1673 bss_conf->use_short_preamble);
1674 if (bss_conf->use_short_preamble)
1675 priv->op_flags |= OP_PREAMBLE_SHORT;
1676 else
1677 priv->op_flags &= ~OP_PREAMBLE_SHORT;
1678 }
1679
1680 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1681 ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
1682 bss_conf->use_cts_prot);
1683 if (bss_conf->use_cts_prot &&
1684 hw->conf.channel->band != IEEE80211_BAND_5GHZ)
1685 priv->op_flags |= OP_PROTECT_ENABLE;
1686 else
1687 priv->op_flags &= ~OP_PROTECT_ENABLE;
1688 }
1689
1690 if (changed & BSS_CHANGED_ERP_SLOT) {
1691 if (bss_conf->use_short_slot)
1692 ah->slottime = 9;
1693 else
1694 ah->slottime = 20;
1695
1696 ath9k_hw_init_global_settings(ah);
1697 }
1698
Sujith2c76ef82010-05-17 12:01:18 +05301699 if (changed & BSS_CHANGED_HT)
1700 ath9k_htc_update_rate(priv, vif, bss_conf);
1701
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301702 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301703 mutex_unlock(&priv->mutex);
1704}
1705
1706static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
1707{
1708 struct ath9k_htc_priv *priv = hw->priv;
1709 u64 tsf;
1710
1711 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301712 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301713 tsf = ath9k_hw_gettsf64(priv->ah);
Sujithcb551df2010-06-01 15:14:12 +05301714 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301715 mutex_unlock(&priv->mutex);
1716
1717 return tsf;
1718}
1719
1720static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
1721{
1722 struct ath9k_htc_priv *priv = hw->priv;
1723
1724 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301725 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301726 ath9k_hw_settsf64(priv->ah, tsf);
Sujithcb551df2010-06-01 15:14:12 +05301727 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301728 mutex_unlock(&priv->mutex);
1729}
1730
1731static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
1732{
1733 struct ath9k_htc_priv *priv = hw->priv;
1734
1735 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301736 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301737 ath9k_hw_reset_tsf(priv->ah);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301738 ath9k_htc_ps_restore(priv);
Sujithcb551df2010-06-01 15:14:12 +05301739 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301740}
1741
1742static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
1743 struct ieee80211_vif *vif,
1744 enum ieee80211_ampdu_mlme_action action,
1745 struct ieee80211_sta *sta,
1746 u16 tid, u16 *ssn)
1747{
1748 struct ath9k_htc_priv *priv = hw->priv;
1749 struct ath9k_htc_aggr_work *work = &priv->aggr_work;
1750 struct ath9k_htc_sta *ista;
1751
1752 switch (action) {
1753 case IEEE80211_AMPDU_RX_START:
1754 break;
1755 case IEEE80211_AMPDU_RX_STOP:
1756 break;
1757 case IEEE80211_AMPDU_TX_START:
1758 case IEEE80211_AMPDU_TX_STOP:
1759 if (!(priv->op_flags & OP_TXAGGR))
1760 return -ENOTSUPP;
1761 memcpy(work->sta_addr, sta->addr, ETH_ALEN);
1762 work->hw = hw;
1763 work->vif = vif;
1764 work->action = action;
1765 work->tid = tid;
1766 ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0);
1767 break;
1768 case IEEE80211_AMPDU_TX_OPERATIONAL:
1769 ista = (struct ath9k_htc_sta *) sta->drv_priv;
1770 ista->tid_state[tid] = AGGR_OPERATIONAL;
1771 break;
1772 default:
1773 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
1774 "Unknown AMPDU action\n");
1775 }
1776
1777 return 0;
1778}
1779
1780static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
1781{
1782 struct ath9k_htc_priv *priv = hw->priv;
1783
1784 mutex_lock(&priv->mutex);
1785 spin_lock_bh(&priv->beacon_lock);
1786 priv->op_flags |= OP_SCANNING;
1787 spin_unlock_bh(&priv->beacon_lock);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301788 cancel_work_sync(&priv->ps_work);
Sujithfb9987d2010-03-17 14:25:25 +05301789 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1790 mutex_unlock(&priv->mutex);
1791}
1792
1793static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
1794{
1795 struct ath9k_htc_priv *priv = hw->priv;
1796
1797 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301798 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301799 spin_lock_bh(&priv->beacon_lock);
1800 priv->op_flags &= ~OP_SCANNING;
1801 spin_unlock_bh(&priv->beacon_lock);
1802 priv->op_flags |= OP_FULL_RESET;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301803 if (priv->op_flags & OP_ASSOCIATED)
Sujithfcb93922010-04-16 11:53:48 +05301804 ath9k_htc_beacon_config(priv, priv->vif);
Sujithfb9987d2010-03-17 14:25:25 +05301805 ath_start_ani(priv);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301806 ath9k_htc_ps_restore(priv);
Sujithcb551df2010-06-01 15:14:12 +05301807 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301808}
1809
1810static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1811{
1812 return 0;
1813}
1814
1815static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
1816 u8 coverage_class)
1817{
1818 struct ath9k_htc_priv *priv = hw->priv;
1819
1820 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301821 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301822 priv->ah->coverage_class = coverage_class;
1823 ath9k_hw_init_global_settings(priv->ah);
Sujithcb551df2010-06-01 15:14:12 +05301824 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301825 mutex_unlock(&priv->mutex);
1826}
1827
1828struct ieee80211_ops ath9k_htc_ops = {
1829 .tx = ath9k_htc_tx,
1830 .start = ath9k_htc_start,
1831 .stop = ath9k_htc_stop,
1832 .add_interface = ath9k_htc_add_interface,
1833 .remove_interface = ath9k_htc_remove_interface,
1834 .config = ath9k_htc_config,
1835 .configure_filter = ath9k_htc_configure_filter,
1836 .sta_notify = ath9k_htc_sta_notify,
1837 .conf_tx = ath9k_htc_conf_tx,
1838 .bss_info_changed = ath9k_htc_bss_info_changed,
1839 .set_key = ath9k_htc_set_key,
1840 .get_tsf = ath9k_htc_get_tsf,
1841 .set_tsf = ath9k_htc_set_tsf,
1842 .reset_tsf = ath9k_htc_reset_tsf,
1843 .ampdu_action = ath9k_htc_ampdu_action,
1844 .sw_scan_start = ath9k_htc_sw_scan_start,
1845 .sw_scan_complete = ath9k_htc_sw_scan_complete,
1846 .set_rts_threshold = ath9k_htc_set_rts_threshold,
1847 .rfkill_poll = ath9k_htc_rfkill_poll_state,
1848 .set_coverage_class = ath9k_htc_set_coverage_class,
1849};