blob: ae84c7bf355a7b90b68cb7400aab05f940c53d47 [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);
1360 return ret;
1361}
1362
1363static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
1364 struct ieee80211_vif *vif)
1365{
1366 struct ath9k_htc_priv *priv = hw->priv;
1367 struct ath_common *common = ath9k_hw_common(priv->ah);
1368 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1369 struct ath9k_htc_target_vif hvif;
1370 int ret = 0;
1371 u8 cmd_rsp;
1372
1373 ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
1374
1375 mutex_lock(&priv->mutex);
1376
1377 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1378 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1379 hvif.index = avp->index;
1380 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
1381 priv->nvifs--;
1382
1383 ath9k_htc_remove_station(priv, vif, NULL);
Sujithfb9987d2010-03-17 14:25:25 +05301384 priv->vif = NULL;
1385
1386 mutex_unlock(&priv->mutex);
1387}
1388
1389static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
1390{
1391 struct ath9k_htc_priv *priv = hw->priv;
1392 struct ath_common *common = ath9k_hw_common(priv->ah);
1393 struct ieee80211_conf *conf = &hw->conf;
1394
1395 mutex_lock(&priv->mutex);
1396
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301397 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1398 bool enable_radio = false;
1399 bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
1400
1401 if (!idle && priv->ps_idle)
1402 enable_radio = true;
1403
1404 priv->ps_idle = idle;
1405
1406 if (enable_radio) {
1407 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
Sujith881ac6a2010-06-01 15:14:11 +05301408 ath9k_htc_radio_enable(hw);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301409 ath_print(common, ATH_DBG_CONFIG,
1410 "not-idle: enabling radio\n");
1411 }
1412 }
1413
Sujithfb9987d2010-03-17 14:25:25 +05301414 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1415 struct ieee80211_channel *curchan = hw->conf.channel;
1416 int pos = curchan->hw_value;
Sujithfb9987d2010-03-17 14:25:25 +05301417
1418 ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
1419 curchan->center_freq);
1420
Sujithfb9987d2010-03-17 14:25:25 +05301421 ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
1422
1423 if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
1424 ath_print(common, ATH_DBG_FATAL,
1425 "Unable to set channel\n");
1426 mutex_unlock(&priv->mutex);
1427 return -EINVAL;
1428 }
1429
1430 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301431 if (changed & IEEE80211_CONF_CHANGE_PS) {
1432 if (conf->flags & IEEE80211_CONF_PS) {
1433 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
1434 priv->ps_enabled = true;
1435 } else {
1436 priv->ps_enabled = false;
1437 cancel_work_sync(&priv->ps_work);
1438 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1439 }
1440 }
Sujithfb9987d2010-03-17 14:25:25 +05301441
1442 if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
1443 if (conf->flags & IEEE80211_CONF_MONITOR) {
1444 if (ath9k_htc_add_monitor_interface(priv))
1445 ath_print(common, ATH_DBG_FATAL,
1446 "Failed to set monitor mode\n");
1447 else
1448 ath_print(common, ATH_DBG_CONFIG,
1449 "HW opmode set to Monitor mode\n");
1450 }
1451 }
1452
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301453 if (priv->ps_idle) {
1454 ath_print(common, ATH_DBG_CONFIG,
1455 "idle: disabling radio\n");
Sujith881ac6a2010-06-01 15:14:11 +05301456 ath9k_htc_radio_disable(hw);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301457 }
1458
Sujithfb9987d2010-03-17 14:25:25 +05301459 mutex_unlock(&priv->mutex);
1460
1461 return 0;
1462}
1463
1464#define SUPPORTED_FILTERS \
1465 (FIF_PROMISC_IN_BSS | \
1466 FIF_ALLMULTI | \
1467 FIF_CONTROL | \
1468 FIF_PSPOLL | \
1469 FIF_OTHER_BSS | \
1470 FIF_BCN_PRBRESP_PROMISC | \
1471 FIF_FCSFAIL)
1472
1473static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
1474 unsigned int changed_flags,
1475 unsigned int *total_flags,
1476 u64 multicast)
1477{
1478 struct ath9k_htc_priv *priv = hw->priv;
1479 u32 rfilt;
1480
1481 mutex_lock(&priv->mutex);
1482
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301483 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301484 changed_flags &= SUPPORTED_FILTERS;
1485 *total_flags &= SUPPORTED_FILTERS;
1486
1487 priv->rxfilter = *total_flags;
Sujith0995d112010-03-29 16:07:09 +05301488 rfilt = ath9k_htc_calcrxfilter(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301489 ath9k_hw_setrxfilter(priv->ah, rfilt);
1490
1491 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
1492 "Set HW RX filter: 0x%x\n", rfilt);
1493
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301494 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301495 mutex_unlock(&priv->mutex);
1496}
1497
1498static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
1499 struct ieee80211_vif *vif,
1500 enum sta_notify_cmd cmd,
1501 struct ieee80211_sta *sta)
1502{
1503 struct ath9k_htc_priv *priv = hw->priv;
1504 int ret;
1505
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301506 mutex_lock(&priv->mutex);
1507
Sujithfb9987d2010-03-17 14:25:25 +05301508 switch (cmd) {
1509 case STA_NOTIFY_ADD:
1510 ret = ath9k_htc_add_station(priv, vif, sta);
1511 if (!ret)
Sujith0d425a72010-05-17 12:01:16 +05301512 ath9k_htc_init_rate(priv, sta);
Sujithfb9987d2010-03-17 14:25:25 +05301513 break;
1514 case STA_NOTIFY_REMOVE:
1515 ath9k_htc_remove_station(priv, vif, sta);
1516 break;
1517 default:
1518 break;
1519 }
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301520
1521 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301522}
1523
1524static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
1525 const struct ieee80211_tx_queue_params *params)
1526{
1527 struct ath9k_htc_priv *priv = hw->priv;
1528 struct ath_common *common = ath9k_hw_common(priv->ah);
1529 struct ath9k_tx_queue_info qi;
1530 int ret = 0, qnum;
1531
1532 if (queue >= WME_NUM_AC)
1533 return 0;
1534
1535 mutex_lock(&priv->mutex);
1536
1537 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
1538
1539 qi.tqi_aifs = params->aifs;
1540 qi.tqi_cwmin = params->cw_min;
1541 qi.tqi_cwmax = params->cw_max;
1542 qi.tqi_burstTime = params->txop;
1543
1544 qnum = get_hw_qnum(queue, priv->hwq_map);
1545
1546 ath_print(common, ATH_DBG_CONFIG,
1547 "Configure tx [queue/hwq] [%d/%d], "
1548 "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
1549 queue, qnum, params->aifs, params->cw_min,
1550 params->cw_max, params->txop);
1551
Sujithe1572c52010-03-24 13:42:13 +05301552 ret = ath_htc_txq_update(priv, qnum, &qi);
Sujithfb9987d2010-03-17 14:25:25 +05301553 if (ret)
1554 ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
1555
1556 mutex_unlock(&priv->mutex);
1557
1558 return ret;
1559}
1560
1561static int ath9k_htc_set_key(struct ieee80211_hw *hw,
1562 enum set_key_cmd cmd,
1563 struct ieee80211_vif *vif,
1564 struct ieee80211_sta *sta,
1565 struct ieee80211_key_conf *key)
1566{
1567 struct ath9k_htc_priv *priv = hw->priv;
1568 struct ath_common *common = ath9k_hw_common(priv->ah);
1569 int ret = 0;
1570
Sujithe1572c52010-03-24 13:42:13 +05301571 if (htc_modparam_nohwcrypt)
Sujithfb9987d2010-03-17 14:25:25 +05301572 return -ENOSPC;
1573
1574 mutex_lock(&priv->mutex);
1575 ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301576 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301577
1578 switch (cmd) {
1579 case SET_KEY:
1580 ret = ath9k_cmn_key_config(common, vif, sta, key);
1581 if (ret >= 0) {
1582 key->hw_key_idx = ret;
1583 /* push IV and Michael MIC generation to stack */
1584 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
1585 if (key->alg == ALG_TKIP)
1586 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
1587 if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
1588 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
1589 ret = 0;
1590 }
1591 break;
1592 case DISABLE_KEY:
1593 ath9k_cmn_key_delete(common, key);
1594 break;
1595 default:
1596 ret = -EINVAL;
1597 }
1598
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301599 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301600 mutex_unlock(&priv->mutex);
1601
1602 return ret;
1603}
1604
1605static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
1606 struct ieee80211_vif *vif,
1607 struct ieee80211_bss_conf *bss_conf,
1608 u32 changed)
1609{
1610 struct ath9k_htc_priv *priv = hw->priv;
1611 struct ath_hw *ah = priv->ah;
1612 struct ath_common *common = ath9k_hw_common(ah);
1613
1614 mutex_lock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301615 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301616
1617 if (changed & BSS_CHANGED_ASSOC) {
1618 common->curaid = bss_conf->assoc ?
1619 bss_conf->aid : 0;
1620 ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
1621 bss_conf->assoc);
1622
1623 if (bss_conf->assoc) {
1624 priv->op_flags |= OP_ASSOCIATED;
1625 ath_start_ani(priv);
1626 } else {
1627 priv->op_flags &= ~OP_ASSOCIATED;
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301628 cancel_work_sync(&priv->ps_work);
Sujithfb9987d2010-03-17 14:25:25 +05301629 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1630 }
1631 }
1632
1633 if (changed & BSS_CHANGED_BSSID) {
1634 /* Set BSSID */
1635 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1636 ath9k_hw_write_associd(ah);
1637
1638 ath_print(common, ATH_DBG_CONFIG,
1639 "BSSID: %pM aid: 0x%x\n",
1640 common->curbssid, common->curaid);
1641 }
1642
1643 if ((changed & BSS_CHANGED_BEACON_INT) ||
1644 (changed & BSS_CHANGED_BEACON) ||
1645 ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1646 bss_conf->enable_beacon)) {
1647 priv->op_flags |= OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301648 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301649 }
1650
Sujithfb9987d2010-03-17 14:25:25 +05301651 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1652 !bss_conf->enable_beacon) {
1653 priv->op_flags &= ~OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301654 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301655 }
1656
1657 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1658 ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
1659 bss_conf->use_short_preamble);
1660 if (bss_conf->use_short_preamble)
1661 priv->op_flags |= OP_PREAMBLE_SHORT;
1662 else
1663 priv->op_flags &= ~OP_PREAMBLE_SHORT;
1664 }
1665
1666 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1667 ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
1668 bss_conf->use_cts_prot);
1669 if (bss_conf->use_cts_prot &&
1670 hw->conf.channel->band != IEEE80211_BAND_5GHZ)
1671 priv->op_flags |= OP_PROTECT_ENABLE;
1672 else
1673 priv->op_flags &= ~OP_PROTECT_ENABLE;
1674 }
1675
1676 if (changed & BSS_CHANGED_ERP_SLOT) {
1677 if (bss_conf->use_short_slot)
1678 ah->slottime = 9;
1679 else
1680 ah->slottime = 20;
1681
1682 ath9k_hw_init_global_settings(ah);
1683 }
1684
Sujith2c76ef82010-05-17 12:01:18 +05301685 if (changed & BSS_CHANGED_HT)
1686 ath9k_htc_update_rate(priv, vif, bss_conf);
1687
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301688 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301689 mutex_unlock(&priv->mutex);
1690}
1691
1692static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
1693{
1694 struct ath9k_htc_priv *priv = hw->priv;
1695 u64 tsf;
1696
1697 mutex_lock(&priv->mutex);
1698 tsf = ath9k_hw_gettsf64(priv->ah);
1699 mutex_unlock(&priv->mutex);
1700
1701 return tsf;
1702}
1703
1704static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
1705{
1706 struct ath9k_htc_priv *priv = hw->priv;
1707
1708 mutex_lock(&priv->mutex);
1709 ath9k_hw_settsf64(priv->ah, tsf);
1710 mutex_unlock(&priv->mutex);
1711}
1712
1713static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
1714{
1715 struct ath9k_htc_priv *priv = hw->priv;
1716
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301717 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301718 mutex_lock(&priv->mutex);
1719 ath9k_hw_reset_tsf(priv->ah);
1720 mutex_unlock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301721 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301722}
1723
1724static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
1725 struct ieee80211_vif *vif,
1726 enum ieee80211_ampdu_mlme_action action,
1727 struct ieee80211_sta *sta,
1728 u16 tid, u16 *ssn)
1729{
1730 struct ath9k_htc_priv *priv = hw->priv;
1731 struct ath9k_htc_aggr_work *work = &priv->aggr_work;
1732 struct ath9k_htc_sta *ista;
1733
1734 switch (action) {
1735 case IEEE80211_AMPDU_RX_START:
1736 break;
1737 case IEEE80211_AMPDU_RX_STOP:
1738 break;
1739 case IEEE80211_AMPDU_TX_START:
1740 case IEEE80211_AMPDU_TX_STOP:
1741 if (!(priv->op_flags & OP_TXAGGR))
1742 return -ENOTSUPP;
1743 memcpy(work->sta_addr, sta->addr, ETH_ALEN);
1744 work->hw = hw;
1745 work->vif = vif;
1746 work->action = action;
1747 work->tid = tid;
1748 ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0);
1749 break;
1750 case IEEE80211_AMPDU_TX_OPERATIONAL:
1751 ista = (struct ath9k_htc_sta *) sta->drv_priv;
1752 ista->tid_state[tid] = AGGR_OPERATIONAL;
1753 break;
1754 default:
1755 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
1756 "Unknown AMPDU action\n");
1757 }
1758
1759 return 0;
1760}
1761
1762static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
1763{
1764 struct ath9k_htc_priv *priv = hw->priv;
1765
1766 mutex_lock(&priv->mutex);
1767 spin_lock_bh(&priv->beacon_lock);
1768 priv->op_flags |= OP_SCANNING;
1769 spin_unlock_bh(&priv->beacon_lock);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301770 cancel_work_sync(&priv->ps_work);
Sujithfb9987d2010-03-17 14:25:25 +05301771 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1772 mutex_unlock(&priv->mutex);
1773}
1774
1775static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
1776{
1777 struct ath9k_htc_priv *priv = hw->priv;
1778
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301779 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301780 mutex_lock(&priv->mutex);
1781 spin_lock_bh(&priv->beacon_lock);
1782 priv->op_flags &= ~OP_SCANNING;
1783 spin_unlock_bh(&priv->beacon_lock);
1784 priv->op_flags |= OP_FULL_RESET;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301785 if (priv->op_flags & OP_ASSOCIATED)
Sujithfcb93922010-04-16 11:53:48 +05301786 ath9k_htc_beacon_config(priv, priv->vif);
Sujithfb9987d2010-03-17 14:25:25 +05301787 ath_start_ani(priv);
1788 mutex_unlock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301789 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301790}
1791
1792static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1793{
1794 return 0;
1795}
1796
1797static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
1798 u8 coverage_class)
1799{
1800 struct ath9k_htc_priv *priv = hw->priv;
1801
1802 mutex_lock(&priv->mutex);
1803 priv->ah->coverage_class = coverage_class;
1804 ath9k_hw_init_global_settings(priv->ah);
1805 mutex_unlock(&priv->mutex);
1806}
1807
1808struct ieee80211_ops ath9k_htc_ops = {
1809 .tx = ath9k_htc_tx,
1810 .start = ath9k_htc_start,
1811 .stop = ath9k_htc_stop,
1812 .add_interface = ath9k_htc_add_interface,
1813 .remove_interface = ath9k_htc_remove_interface,
1814 .config = ath9k_htc_config,
1815 .configure_filter = ath9k_htc_configure_filter,
1816 .sta_notify = ath9k_htc_sta_notify,
1817 .conf_tx = ath9k_htc_conf_tx,
1818 .bss_info_changed = ath9k_htc_bss_info_changed,
1819 .set_key = ath9k_htc_set_key,
1820 .get_tsf = ath9k_htc_get_tsf,
1821 .set_tsf = ath9k_htc_set_tsf,
1822 .reset_tsf = ath9k_htc_reset_tsf,
1823 .ampdu_action = ath9k_htc_ampdu_action,
1824 .sw_scan_start = ath9k_htc_sw_scan_start,
1825 .sw_scan_complete = ath9k_htc_sw_scan_complete,
1826 .set_rts_threshold = ath9k_htc_set_rts_threshold,
1827 .rfkill_poll = ath9k_htc_rfkill_poll_state,
1828 .set_coverage_class = ath9k_htc_set_coverage_class,
1829};