blob: 1c7263e3d1de86a477c41ba5fa03d19150987314 [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;
Sujith29d90752010-06-02 15:53:43 +0530328 tcap.tx_chainmask_legacy = priv->ah->caps.tx_chainmask;
Sujithfb9987d2010-03-17 14:25:25 +0530329 tcap.protmode = 1;
Sujith29d90752010-06-02 15:53:43 +0530330 tcap.tx_chainmask = priv->ah->caps.tx_chainmask;
Sujithfb9987d2010-03-17 14:25:25 +0530331
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
Sujithea46e642010-06-02 15:53:50 +0530346 sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band];
Sujithfb9987d2010-03-17 14:25:25 +0530347
348 for (i = 0, j = 0; i < sband->n_bitrates; i++) {
349 if (sta->supp_rates[sband->band] & BIT(i)) {
Sujith0d425a72010-05-17 12:01:16 +0530350 trate->rates.legacy_rates.rs_rates[j]
Sujithfb9987d2010-03-17 14:25:25 +0530351 = (sband->bitrates[i].bitrate * 2) / 10;
352 j++;
353 }
354 }
Sujith0d425a72010-05-17 12:01:16 +0530355 trate->rates.legacy_rates.rs_nrates = j;
Sujithfb9987d2010-03-17 14:25:25 +0530356
357 if (sta->ht_cap.ht_supported) {
358 for (i = 0, j = 0; i < 77; i++) {
359 if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
Sujith0d425a72010-05-17 12:01:16 +0530360 trate->rates.ht_rates.rs_rates[j++] = i;
Sujithfb9987d2010-03-17 14:25:25 +0530361 if (j == ATH_HTC_RATE_MAX)
362 break;
363 }
Sujith0d425a72010-05-17 12:01:16 +0530364 trate->rates.ht_rates.rs_nrates = j;
Sujithfb9987d2010-03-17 14:25:25 +0530365
366 caps = WLAN_RC_HT_FLAG;
Sujith29d90752010-06-02 15:53:43 +0530367 if (priv->ah->caps.tx_chainmask != 1 &&
368 ath9k_hw_getcapability(priv->ah, ATH9K_CAP_DS, 0, NULL)) {
369 if (sta->ht_cap.mcs.rx_mask[1])
370 caps |= WLAN_RC_DS_FLAG;
371 }
Sujithfb9987d2010-03-17 14:25:25 +0530372 if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
373 caps |= WLAN_RC_40_FLAG;
Sujithb4dec5e2010-05-17 12:01:19 +0530374 if (conf_is_ht40(&priv->hw->conf) &&
375 (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40))
Sujithfb9987d2010-03-17 14:25:25 +0530376 caps |= WLAN_RC_SGI_FLAG;
Sujithb4dec5e2010-05-17 12:01:19 +0530377 else if (conf_is_ht20(&priv->hw->conf) &&
378 (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20))
379 caps |= WLAN_RC_SGI_FLAG;
Sujithfb9987d2010-03-17 14:25:25 +0530380 }
381
Sujith0d425a72010-05-17 12:01:16 +0530382 trate->sta_index = ista->index;
383 trate->isnew = 1;
384 trate->capflags = cpu_to_be32(caps);
385}
Sujithfb9987d2010-03-17 14:25:25 +0530386
Sujith0d425a72010-05-17 12:01:16 +0530387static int ath9k_htc_send_rate_cmd(struct ath9k_htc_priv *priv,
388 struct ath9k_htc_target_rate *trate)
389{
390 struct ath_common *common = ath9k_hw_common(priv->ah);
391 int ret;
392 u8 cmd_rsp;
393
394 WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, trate);
Sujithfb9987d2010-03-17 14:25:25 +0530395 if (ret) {
396 ath_print(common, ATH_DBG_FATAL,
397 "Unable to initialize Rate information on target\n");
Sujithfb9987d2010-03-17 14:25:25 +0530398 }
399
Sujith0d425a72010-05-17 12:01:16 +0530400 return ret;
Sujithfb9987d2010-03-17 14:25:25 +0530401}
402
Sujith0d425a72010-05-17 12:01:16 +0530403static void ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
404 struct ieee80211_sta *sta)
Sujithfb9987d2010-03-17 14:25:25 +0530405{
Sujithfb9987d2010-03-17 14:25:25 +0530406 struct ath_common *common = ath9k_hw_common(priv->ah);
Sujith0d425a72010-05-17 12:01:16 +0530407 struct ath9k_htc_target_rate trate;
Sujithfb9987d2010-03-17 14:25:25 +0530408 int ret;
Sujithfb9987d2010-03-17 14:25:25 +0530409
Sujith0d425a72010-05-17 12:01:16 +0530410 memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
411 ath9k_htc_setup_rate(priv, sta, &trate);
412 ret = ath9k_htc_send_rate_cmd(priv, &trate);
413 if (!ret)
414 ath_print(common, ATH_DBG_CONFIG,
415 "Updated target sta: %pM, rate caps: 0x%X\n",
416 sta->addr, be32_to_cpu(trate.capflags));
Sujithfb9987d2010-03-17 14:25:25 +0530417}
418
Sujith2c76ef82010-05-17 12:01:18 +0530419static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv,
420 struct ieee80211_vif *vif,
421 struct ieee80211_bss_conf *bss_conf)
422{
423 struct ath_common *common = ath9k_hw_common(priv->ah);
424 struct ath9k_htc_target_rate trate;
425 struct ieee80211_sta *sta;
426 int ret;
427
428 memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
429
430 rcu_read_lock();
431 sta = ieee80211_find_sta(vif, bss_conf->bssid);
432 if (!sta) {
433 rcu_read_unlock();
434 return;
435 }
436 ath9k_htc_setup_rate(priv, sta, &trate);
437 rcu_read_unlock();
438
439 ret = ath9k_htc_send_rate_cmd(priv, &trate);
440 if (!ret)
441 ath_print(common, ATH_DBG_CONFIG,
442 "Updated target sta: %pM, rate caps: 0x%X\n",
443 bss_conf->bssid, be32_to_cpu(trate.capflags));
444}
445
Sujithfb9987d2010-03-17 14:25:25 +0530446static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
447 struct ieee80211_vif *vif,
448 u8 *sta_addr, u8 tid, bool oper)
449{
450 struct ath_common *common = ath9k_hw_common(priv->ah);
451 struct ath9k_htc_target_aggr aggr;
452 struct ieee80211_sta *sta = NULL;
Dan Carpenter277a64d2010-05-08 18:23:20 +0200453 struct ath9k_htc_sta *ista;
Sujithfb9987d2010-03-17 14:25:25 +0530454 int ret = 0;
455 u8 cmd_rsp;
456
Dan Carpenter0730d112010-05-08 18:24:02 +0200457 if (tid >= ATH9K_HTC_MAX_TID)
Sujithfb9987d2010-03-17 14:25:25 +0530458 return -EINVAL;
459
Sujithfb9987d2010-03-17 14:25:25 +0530460 memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
461
Sujithef98c3c2010-03-29 16:07:11 +0530462 rcu_read_lock();
463
464 /* Check if we are able to retrieve the station */
465 sta = ieee80211_find_sta(vif, sta_addr);
466 if (!sta) {
467 rcu_read_unlock();
468 return -EINVAL;
469 }
470
471 ista = (struct ath9k_htc_sta *) sta->drv_priv;
Sujithfb9987d2010-03-17 14:25:25 +0530472
473 if (oper)
474 ista->tid_state[tid] = AGGR_START;
475 else
476 ista->tid_state[tid] = AGGR_STOP;
477
Sujithef98c3c2010-03-29 16:07:11 +0530478 aggr.sta_index = ista->index;
479
480 rcu_read_unlock();
481
482 aggr.tidno = tid;
483 aggr.aggr_enable = oper;
484
Sujithfb9987d2010-03-17 14:25:25 +0530485 WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
486 if (ret)
487 ath_print(common, ATH_DBG_CONFIG,
488 "Unable to %s TX aggregation for (%pM, %d)\n",
489 (oper) ? "start" : "stop", sta->addr, tid);
490 else
491 ath_print(common, ATH_DBG_CONFIG,
492 "%s aggregation for (%pM, %d)\n",
493 (oper) ? "Starting" : "Stopping", sta->addr, tid);
494
495 return ret;
496}
497
498void ath9k_htc_aggr_work(struct work_struct *work)
499{
500 int ret = 0;
501 struct ath9k_htc_priv *priv =
502 container_of(work, struct ath9k_htc_priv,
503 ath9k_aggr_work.work);
504 struct ath9k_htc_aggr_work *wk = &priv->aggr_work;
505
506 mutex_lock(&wk->mutex);
507
508 switch (wk->action) {
509 case IEEE80211_AMPDU_TX_START:
510 ret = ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
511 wk->tid, true);
512 if (!ret)
Johannes Berg5d22c892010-06-10 10:21:40 +0200513 ieee80211_start_tx_ba_cb_irqsafe(wk->vif, wk->sta_addr,
514 wk->tid);
Sujithfb9987d2010-03-17 14:25:25 +0530515 break;
516 case IEEE80211_AMPDU_TX_STOP:
517 ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
518 wk->tid, false);
Johannes Berg5d22c892010-06-10 10:21:40 +0200519 ieee80211_stop_tx_ba_cb_irqsafe(wk->vif, wk->sta_addr, wk->tid);
Sujithfb9987d2010-03-17 14:25:25 +0530520 break;
521 default:
522 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
523 "Unknown AMPDU action\n");
524 }
525
526 mutex_unlock(&wk->mutex);
527}
528
529/*********/
530/* DEBUG */
531/*********/
532
533#ifdef CONFIG_ATH9K_HTC_DEBUGFS
534
535static int ath9k_debugfs_open(struct inode *inode, struct file *file)
536{
537 file->private_data = inode->i_private;
538 return 0;
539}
540
541static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
542 size_t count, loff_t *ppos)
543{
544 struct ath9k_htc_priv *priv =
545 (struct ath9k_htc_priv *) file->private_data;
546 struct ath9k_htc_target_stats cmd_rsp;
547 char buf[512];
548 unsigned int len = 0;
549 int ret = 0;
550
551 memset(&cmd_rsp, 0, sizeof(cmd_rsp));
552
553 WMI_CMD(WMI_TGT_STATS_CMDID);
554 if (ret)
555 return -EINVAL;
556
557
558 len += snprintf(buf + len, sizeof(buf) - len,
559 "%19s : %10u\n", "TX Short Retries",
560 be32_to_cpu(cmd_rsp.tx_shortretry));
561 len += snprintf(buf + len, sizeof(buf) - len,
562 "%19s : %10u\n", "TX Long Retries",
563 be32_to_cpu(cmd_rsp.tx_longretry));
564 len += snprintf(buf + len, sizeof(buf) - len,
565 "%19s : %10u\n", "TX Xretries",
566 be32_to_cpu(cmd_rsp.tx_xretries));
567 len += snprintf(buf + len, sizeof(buf) - len,
568 "%19s : %10u\n", "TX Unaggr. Xretries",
569 be32_to_cpu(cmd_rsp.ht_txunaggr_xretry));
570 len += snprintf(buf + len, sizeof(buf) - len,
571 "%19s : %10u\n", "TX Xretries (HT)",
572 be32_to_cpu(cmd_rsp.ht_tx_xretries));
573 len += snprintf(buf + len, sizeof(buf) - len,
574 "%19s : %10u\n", "TX Rate", priv->debug.txrate);
575
576 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
577}
578
579static const struct file_operations fops_tgt_stats = {
580 .read = read_file_tgt_stats,
581 .open = ath9k_debugfs_open,
582 .owner = THIS_MODULE
583};
584
585static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
586 size_t count, loff_t *ppos)
587{
588 struct ath9k_htc_priv *priv =
589 (struct ath9k_htc_priv *) file->private_data;
590 char buf[512];
591 unsigned int len = 0;
592
593 len += snprintf(buf + len, sizeof(buf) - len,
594 "%20s : %10u\n", "Buffers queued",
595 priv->debug.tx_stats.buf_queued);
596 len += snprintf(buf + len, sizeof(buf) - len,
597 "%20s : %10u\n", "Buffers completed",
598 priv->debug.tx_stats.buf_completed);
599 len += snprintf(buf + len, sizeof(buf) - len,
600 "%20s : %10u\n", "SKBs queued",
601 priv->debug.tx_stats.skb_queued);
602 len += snprintf(buf + len, sizeof(buf) - len,
603 "%20s : %10u\n", "SKBs completed",
604 priv->debug.tx_stats.skb_completed);
Sujitheac8e382010-04-16 11:54:00 +0530605 len += snprintf(buf + len, sizeof(buf) - len,
606 "%20s : %10u\n", "SKBs dropped",
607 priv->debug.tx_stats.skb_dropped);
Sujithfb9987d2010-03-17 14:25:25 +0530608
Sujith2edb4582010-05-14 11:18:54 +0530609 len += snprintf(buf + len, sizeof(buf) - len,
610 "%20s : %10u\n", "BE queued",
611 priv->debug.tx_stats.queue_stats[WME_AC_BE]);
612 len += snprintf(buf + len, sizeof(buf) - len,
613 "%20s : %10u\n", "BK queued",
614 priv->debug.tx_stats.queue_stats[WME_AC_BK]);
615 len += snprintf(buf + len, sizeof(buf) - len,
616 "%20s : %10u\n", "VI queued",
617 priv->debug.tx_stats.queue_stats[WME_AC_VI]);
618 len += snprintf(buf + len, sizeof(buf) - len,
619 "%20s : %10u\n", "VO queued",
620 priv->debug.tx_stats.queue_stats[WME_AC_VO]);
621
Sujithfb9987d2010-03-17 14:25:25 +0530622 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
623}
624
625static const struct file_operations fops_xmit = {
626 .read = read_file_xmit,
627 .open = ath9k_debugfs_open,
628 .owner = THIS_MODULE
629};
630
631static ssize_t read_file_recv(struct file *file, char __user *user_buf,
632 size_t count, loff_t *ppos)
633{
634 struct ath9k_htc_priv *priv =
635 (struct ath9k_htc_priv *) file->private_data;
636 char buf[512];
637 unsigned int len = 0;
638
639 len += snprintf(buf + len, sizeof(buf) - len,
640 "%20s : %10u\n", "SKBs allocated",
641 priv->debug.rx_stats.skb_allocated);
642 len += snprintf(buf + len, sizeof(buf) - len,
643 "%20s : %10u\n", "SKBs completed",
644 priv->debug.rx_stats.skb_completed);
645 len += snprintf(buf + len, sizeof(buf) - len,
646 "%20s : %10u\n", "SKBs Dropped",
647 priv->debug.rx_stats.skb_dropped);
648
649 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
650}
651
652static const struct file_operations fops_recv = {
653 .read = read_file_recv,
654 .open = ath9k_debugfs_open,
655 .owner = THIS_MODULE
656};
657
Sujithe1572c52010-03-24 13:42:13 +0530658int ath9k_htc_init_debug(struct ath_hw *ah)
Sujithfb9987d2010-03-17 14:25:25 +0530659{
660 struct ath_common *common = ath9k_hw_common(ah);
661 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
662
663 if (!ath9k_debugfs_root)
664 return -ENOENT;
665
666 priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy),
667 ath9k_debugfs_root);
668 if (!priv->debug.debugfs_phy)
669 goto err;
670
671 priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR,
672 priv->debug.debugfs_phy,
673 priv, &fops_tgt_stats);
674 if (!priv->debug.debugfs_tgt_stats)
675 goto err;
676
677
678 priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR,
679 priv->debug.debugfs_phy,
680 priv, &fops_xmit);
681 if (!priv->debug.debugfs_xmit)
682 goto err;
683
684 priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR,
685 priv->debug.debugfs_phy,
686 priv, &fops_recv);
687 if (!priv->debug.debugfs_recv)
688 goto err;
689
690 return 0;
691
692err:
Sujithe1572c52010-03-24 13:42:13 +0530693 ath9k_htc_exit_debug(ah);
Sujithfb9987d2010-03-17 14:25:25 +0530694 return -ENOMEM;
695}
696
Sujithe1572c52010-03-24 13:42:13 +0530697void ath9k_htc_exit_debug(struct ath_hw *ah)
Sujithfb9987d2010-03-17 14:25:25 +0530698{
699 struct ath_common *common = ath9k_hw_common(ah);
700 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
701
702 debugfs_remove(priv->debug.debugfs_recv);
703 debugfs_remove(priv->debug.debugfs_xmit);
704 debugfs_remove(priv->debug.debugfs_tgt_stats);
705 debugfs_remove(priv->debug.debugfs_phy);
706}
707
Sujithe1572c52010-03-24 13:42:13 +0530708int ath9k_htc_debug_create_root(void)
Sujithfb9987d2010-03-17 14:25:25 +0530709{
710 ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
711 if (!ath9k_debugfs_root)
712 return -ENOENT;
713
714 return 0;
715}
716
Sujithe1572c52010-03-24 13:42:13 +0530717void ath9k_htc_debug_remove_root(void)
Sujithfb9987d2010-03-17 14:25:25 +0530718{
719 debugfs_remove(ath9k_debugfs_root);
720 ath9k_debugfs_root = NULL;
721}
722
723#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
724
725/*******/
726/* ANI */
727/*******/
728
729static void ath_start_ani(struct ath9k_htc_priv *priv)
730{
731 struct ath_common *common = ath9k_hw_common(priv->ah);
732 unsigned long timestamp = jiffies_to_msecs(jiffies);
733
734 common->ani.longcal_timer = timestamp;
735 common->ani.shortcal_timer = timestamp;
736 common->ani.checkani_timer = timestamp;
737
738 ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
739 msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
740}
741
742void ath9k_ani_work(struct work_struct *work)
743{
744 struct ath9k_htc_priv *priv =
745 container_of(work, struct ath9k_htc_priv,
746 ath9k_ani_work.work);
747 struct ath_hw *ah = priv->ah;
748 struct ath_common *common = ath9k_hw_common(ah);
749 bool longcal = false;
750 bool shortcal = false;
751 bool aniflag = false;
752 unsigned int timestamp = jiffies_to_msecs(jiffies);
753 u32 cal_interval, short_cal_interval;
754
755 short_cal_interval = ATH_STA_SHORT_CALINTERVAL;
756
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530757 /* Only calibrate if awake */
758 if (ah->power_mode != ATH9K_PM_AWAKE)
759 goto set_timer;
760
Sujithfb9987d2010-03-17 14:25:25 +0530761 /* Long calibration runs independently of short calibration. */
762 if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
763 longcal = true;
764 ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
765 common->ani.longcal_timer = timestamp;
766 }
767
768 /* Short calibration applies only while caldone is false */
769 if (!common->ani.caldone) {
770 if ((timestamp - common->ani.shortcal_timer) >=
771 short_cal_interval) {
772 shortcal = true;
773 ath_print(common, ATH_DBG_ANI,
774 "shortcal @%lu\n", jiffies);
775 common->ani.shortcal_timer = timestamp;
776 common->ani.resetcal_timer = timestamp;
777 }
778 } else {
779 if ((timestamp - common->ani.resetcal_timer) >=
780 ATH_RESTART_CALINTERVAL) {
781 common->ani.caldone = ath9k_hw_reset_calvalid(ah);
782 if (common->ani.caldone)
783 common->ani.resetcal_timer = timestamp;
784 }
785 }
786
787 /* Verify whether we must check ANI */
788 if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
789 aniflag = true;
790 common->ani.checkani_timer = timestamp;
791 }
792
793 /* Skip all processing if there's nothing to do. */
794 if (longcal || shortcal || aniflag) {
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530795
796 ath9k_htc_ps_wakeup(priv);
797
Sujithfb9987d2010-03-17 14:25:25 +0530798 /* Call ANI routine if necessary */
799 if (aniflag)
800 ath9k_hw_ani_monitor(ah, ah->curchan);
801
802 /* Perform calibration if necessary */
803 if (longcal || shortcal) {
804 common->ani.caldone =
805 ath9k_hw_calibrate(ah, ah->curchan,
806 common->rx_chainmask,
807 longcal);
808
809 if (longcal)
810 common->ani.noise_floor =
811 ath9k_hw_getchan_noise(ah, ah->curchan);
812
813 ath_print(common, ATH_DBG_ANI,
814 " calibrate chan %u/%x nf: %d\n",
815 ah->curchan->channel,
816 ah->curchan->channelFlags,
817 common->ani.noise_floor);
818 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530819
820 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530821 }
822
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530823set_timer:
Sujithfb9987d2010-03-17 14:25:25 +0530824 /*
825 * Set timer interval based on previous results.
826 * The interval must be the shortest necessary to satisfy ANI,
827 * short calibration and long calibration.
828 */
829 cal_interval = ATH_LONG_CALINTERVAL;
830 if (priv->ah->config.enable_ani)
831 cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
832 if (!common->ani.caldone)
833 cal_interval = min(cal_interval, (u32)short_cal_interval);
834
835 ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
836 msecs_to_jiffies(cal_interval));
837}
838
839/*******/
840/* LED */
841/*******/
842
843static void ath9k_led_blink_work(struct work_struct *work)
844{
845 struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
846 ath9k_led_blink_work.work);
847
848 if (!(priv->op_flags & OP_LED_ASSOCIATED))
849 return;
850
851 if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
852 (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
853 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
854 else
855 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
856 (priv->op_flags & OP_LED_ON) ? 1 : 0);
857
858 ieee80211_queue_delayed_work(priv->hw,
859 &priv->ath9k_led_blink_work,
860 (priv->op_flags & OP_LED_ON) ?
861 msecs_to_jiffies(priv->led_off_duration) :
862 msecs_to_jiffies(priv->led_on_duration));
863
864 priv->led_on_duration = priv->led_on_cnt ?
865 max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
866 ATH_LED_ON_DURATION_IDLE;
867 priv->led_off_duration = priv->led_off_cnt ?
868 max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
869 ATH_LED_OFF_DURATION_IDLE;
870 priv->led_on_cnt = priv->led_off_cnt = 0;
871
872 if (priv->op_flags & OP_LED_ON)
873 priv->op_flags &= ~OP_LED_ON;
874 else
875 priv->op_flags |= OP_LED_ON;
876}
877
878static void ath9k_led_brightness_work(struct work_struct *work)
879{
880 struct ath_led *led = container_of(work, struct ath_led,
881 brightness_work.work);
882 struct ath9k_htc_priv *priv = led->priv;
883
884 switch (led->brightness) {
885 case LED_OFF:
886 if (led->led_type == ATH_LED_ASSOC ||
887 led->led_type == ATH_LED_RADIO) {
888 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
889 (led->led_type == ATH_LED_RADIO));
890 priv->op_flags &= ~OP_LED_ASSOCIATED;
891 if (led->led_type == ATH_LED_RADIO)
892 priv->op_flags &= ~OP_LED_ON;
893 } else {
894 priv->led_off_cnt++;
895 }
896 break;
897 case LED_FULL:
898 if (led->led_type == ATH_LED_ASSOC) {
899 priv->op_flags |= OP_LED_ASSOCIATED;
900 ieee80211_queue_delayed_work(priv->hw,
901 &priv->ath9k_led_blink_work, 0);
902 } else if (led->led_type == ATH_LED_RADIO) {
903 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
904 priv->op_flags |= OP_LED_ON;
905 } else {
906 priv->led_on_cnt++;
907 }
908 break;
909 default:
910 break;
911 }
912}
913
914static void ath9k_led_brightness(struct led_classdev *led_cdev,
915 enum led_brightness brightness)
916{
917 struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
918 struct ath9k_htc_priv *priv = led->priv;
919
920 led->brightness = brightness;
921 if (!(priv->op_flags & OP_LED_DEINIT))
922 ieee80211_queue_delayed_work(priv->hw,
923 &led->brightness_work, 0);
924}
925
926static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
927{
928 cancel_delayed_work_sync(&priv->radio_led.brightness_work);
929 cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
930 cancel_delayed_work_sync(&priv->tx_led.brightness_work);
931 cancel_delayed_work_sync(&priv->rx_led.brightness_work);
932}
933
934static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
935 char *trigger)
936{
937 int ret;
938
939 led->priv = priv;
940 led->led_cdev.name = led->name;
941 led->led_cdev.default_trigger = trigger;
942 led->led_cdev.brightness_set = ath9k_led_brightness;
943
944 ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
945 if (ret)
946 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
947 "Failed to register led:%s", led->name);
948 else
949 led->registered = 1;
950
951 INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
952
953 return ret;
954}
955
956static void ath9k_unregister_led(struct ath_led *led)
957{
958 if (led->registered) {
959 led_classdev_unregister(&led->led_cdev);
960 led->registered = 0;
961 }
962}
963
964void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
965{
966 priv->op_flags |= OP_LED_DEINIT;
967 ath9k_unregister_led(&priv->assoc_led);
968 priv->op_flags &= ~OP_LED_ASSOCIATED;
969 ath9k_unregister_led(&priv->tx_led);
970 ath9k_unregister_led(&priv->rx_led);
971 ath9k_unregister_led(&priv->radio_led);
Sujithfb9987d2010-03-17 14:25:25 +0530972}
973
974void ath9k_init_leds(struct ath9k_htc_priv *priv)
975{
976 char *trigger;
977 int ret;
978
979 if (AR_SREV_9287(priv->ah))
980 priv->ah->led_pin = ATH_LED_PIN_9287;
981 else if (AR_SREV_9271(priv->ah))
982 priv->ah->led_pin = ATH_LED_PIN_9271;
983 else
984 priv->ah->led_pin = ATH_LED_PIN_DEF;
985
986 /* Configure gpio 1 for output */
987 ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
988 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
989 /* LED off, active low */
990 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
991
992 INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
993
994 trigger = ieee80211_get_radio_led_name(priv->hw);
995 snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
996 "ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
997 ret = ath9k_register_led(priv, &priv->radio_led, trigger);
998 priv->radio_led.led_type = ATH_LED_RADIO;
999 if (ret)
1000 goto fail;
1001
1002 trigger = ieee80211_get_assoc_led_name(priv->hw);
1003 snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
1004 "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
1005 ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
1006 priv->assoc_led.led_type = ATH_LED_ASSOC;
1007 if (ret)
1008 goto fail;
1009
1010 trigger = ieee80211_get_tx_led_name(priv->hw);
1011 snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
1012 "ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
1013 ret = ath9k_register_led(priv, &priv->tx_led, trigger);
1014 priv->tx_led.led_type = ATH_LED_TX;
1015 if (ret)
1016 goto fail;
1017
1018 trigger = ieee80211_get_rx_led_name(priv->hw);
1019 snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
1020 "ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
1021 ret = ath9k_register_led(priv, &priv->rx_led, trigger);
1022 priv->rx_led.led_type = ATH_LED_RX;
1023 if (ret)
1024 goto fail;
1025
1026 priv->op_flags &= ~OP_LED_DEINIT;
1027
1028 return;
1029
1030fail:
1031 cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
1032 ath9k_deinit_leds(priv);
1033}
1034
1035/*******************/
1036/* Rfkill */
1037/*******************/
1038
1039static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
1040{
1041 return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
1042 priv->ah->rfkill_polarity;
1043}
1044
1045static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
1046{
1047 struct ath9k_htc_priv *priv = hw->priv;
1048 bool blocked = !!ath_is_rfkill_set(priv);
1049
1050 wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
1051}
1052
1053void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
1054{
1055 if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
1056 wiphy_rfkill_start_polling(priv->hw->wiphy);
1057}
1058
Sujith881ac6a2010-06-01 15:14:11 +05301059static void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
1060{
1061 struct ath9k_htc_priv *priv = hw->priv;
1062 struct ath_hw *ah = priv->ah;
1063 struct ath_common *common = ath9k_hw_common(ah);
1064 int ret;
1065 u8 cmd_rsp;
1066
1067 if (!ah->curchan)
1068 ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
1069
1070 /* Reset the HW */
1071 ret = ath9k_hw_reset(ah, ah->curchan, false);
1072 if (ret) {
1073 ath_print(common, ATH_DBG_FATAL,
1074 "Unable to reset hardware; reset status %d "
1075 "(freq %u MHz)\n", ret, ah->curchan->channel);
1076 }
1077
1078 ath_update_txpow(priv);
1079
1080 /* Start RX */
1081 WMI_CMD(WMI_START_RECV_CMDID);
1082 ath9k_host_rx_init(priv);
1083
1084 /* Start TX */
1085 htc_start(priv->htc);
1086 spin_lock_bh(&priv->tx_lock);
1087 priv->tx_queues_stop = false;
1088 spin_unlock_bh(&priv->tx_lock);
1089 ieee80211_wake_queues(hw);
1090
1091 WMI_CMD(WMI_ENABLE_INTR_CMDID);
1092
1093 /* Enable LED */
1094 ath9k_hw_cfg_output(ah, ah->led_pin,
1095 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
1096 ath9k_hw_set_gpio(ah, ah->led_pin, 0);
1097}
1098
1099static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
1100{
1101 struct ath9k_htc_priv *priv = hw->priv;
1102 struct ath_hw *ah = priv->ah;
1103 struct ath_common *common = ath9k_hw_common(ah);
1104 int ret;
1105 u8 cmd_rsp;
1106
1107 ath9k_htc_ps_wakeup(priv);
1108
1109 /* Disable LED */
1110 ath9k_hw_set_gpio(ah, ah->led_pin, 1);
1111 ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
1112
1113 WMI_CMD(WMI_DISABLE_INTR_CMDID);
1114
1115 /* Stop TX */
1116 ieee80211_stop_queues(hw);
1117 htc_stop(priv->htc);
1118 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
1119 skb_queue_purge(&priv->tx_queue);
1120
1121 /* Stop RX */
1122 WMI_CMD(WMI_STOP_RECV_CMDID);
1123
Sujith21d51302010-06-01 15:14:18 +05301124 /*
1125 * The MIB counters have to be disabled here,
1126 * since the target doesn't do it.
1127 */
1128 ath9k_hw_disable_mib_counters(ah);
1129
Sujith881ac6a2010-06-01 15:14:11 +05301130 if (!ah->curchan)
1131 ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
1132
1133 /* Reset the HW */
1134 ret = ath9k_hw_reset(ah, ah->curchan, false);
1135 if (ret) {
1136 ath_print(common, ATH_DBG_FATAL,
1137 "Unable to reset hardware; reset status %d "
1138 "(freq %u MHz)\n", ret, ah->curchan->channel);
1139 }
1140
1141 /* Disable the PHY */
1142 ath9k_hw_phy_disable(ah);
1143
1144 ath9k_htc_ps_restore(priv);
1145 ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
1146}
1147
Sujithfb9987d2010-03-17 14:25:25 +05301148/**********************/
1149/* mac80211 Callbacks */
1150/**********************/
1151
1152static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1153{
1154 struct ieee80211_hdr *hdr;
1155 struct ath9k_htc_priv *priv = hw->priv;
Sujith7757dfe2010-03-29 16:07:17 +05301156 int padpos, padsize, ret;
Sujithfb9987d2010-03-17 14:25:25 +05301157
1158 hdr = (struct ieee80211_hdr *) skb->data;
1159
1160 /* Add the padding after the header if this is not already done */
1161 padpos = ath9k_cmn_padpos(hdr->frame_control);
1162 padsize = padpos & 3;
1163 if (padsize && skb->len > padpos) {
1164 if (skb_headroom(skb) < padsize)
1165 return -1;
1166 skb_push(skb, padsize);
1167 memmove(skb->data, skb->data + padsize, padpos);
1168 }
1169
Sujith7757dfe2010-03-29 16:07:17 +05301170 ret = ath9k_htc_tx_start(priv, skb);
1171 if (ret != 0) {
1172 if (ret == -ENOMEM) {
1173 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1174 "Stopping TX queues\n");
1175 ieee80211_stop_queues(hw);
1176 spin_lock_bh(&priv->tx_lock);
1177 priv->tx_queues_stop = true;
1178 spin_unlock_bh(&priv->tx_lock);
1179 } else {
1180 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1181 "Tx failed");
1182 }
Sujithfb9987d2010-03-17 14:25:25 +05301183 goto fail_tx;
1184 }
1185
1186 return 0;
1187
1188fail_tx:
1189 dev_kfree_skb_any(skb);
1190 return 0;
1191}
1192
Sujith881ac6a2010-06-01 15:14:11 +05301193static int ath9k_htc_start(struct ieee80211_hw *hw)
Sujithfb9987d2010-03-17 14:25:25 +05301194{
1195 struct ath9k_htc_priv *priv = hw->priv;
1196 struct ath_hw *ah = priv->ah;
1197 struct ath_common *common = ath9k_hw_common(ah);
1198 struct ieee80211_channel *curchan = hw->conf.channel;
1199 struct ath9k_channel *init_channel;
1200 int ret = 0;
1201 enum htc_phymode mode;
Sujith7f1f5a02010-04-16 11:54:03 +05301202 __be16 htc_mode;
Sujithfb9987d2010-03-17 14:25:25 +05301203 u8 cmd_rsp;
1204
Sujith881ac6a2010-06-01 15:14:11 +05301205 mutex_lock(&priv->mutex);
1206
Sujithfb9987d2010-03-17 14:25:25 +05301207 ath_print(common, ATH_DBG_CONFIG,
1208 "Starting driver with initial channel: %d MHz\n",
1209 curchan->center_freq);
1210
Sujith21d51302010-06-01 15:14:18 +05301211 /* Ensure that HW is awake before flushing RX */
1212 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1213 WMI_CMD(WMI_FLUSH_RECV_CMDID);
1214
Sujithfb9987d2010-03-17 14:25:25 +05301215 /* setup initial channel */
1216 init_channel = ath9k_cmn_get_curchannel(hw, ah);
1217
1218 /* Reset SERDES registers */
1219 ath9k_hw_configpcipowersave(ah, 0, 0);
1220
1221 ath9k_hw_htc_resetinit(ah);
1222 ret = ath9k_hw_reset(ah, init_channel, false);
1223 if (ret) {
1224 ath_print(common, ATH_DBG_FATAL,
1225 "Unable to reset hardware; reset status %d "
1226 "(freq %u MHz)\n", ret, curchan->center_freq);
Sujith881ac6a2010-06-01 15:14:11 +05301227 mutex_unlock(&priv->mutex);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301228 return ret;
Sujithfb9987d2010-03-17 14:25:25 +05301229 }
1230
1231 ath_update_txpow(priv);
1232
1233 mode = ath9k_htc_get_curmode(priv, init_channel);
1234 htc_mode = cpu_to_be16(mode);
1235 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
Sujithfb9987d2010-03-17 14:25:25 +05301236 WMI_CMD(WMI_ATH_INIT_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301237 WMI_CMD(WMI_START_RECV_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301238
1239 ath9k_host_rx_init(priv);
1240
1241 priv->op_flags &= ~OP_INVALID;
1242 htc_start(priv->htc);
1243
Sujith7757dfe2010-03-29 16:07:17 +05301244 spin_lock_bh(&priv->tx_lock);
1245 priv->tx_queues_stop = false;
1246 spin_unlock_bh(&priv->tx_lock);
1247
1248 ieee80211_wake_queues(hw);
1249
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301250 mutex_unlock(&priv->mutex);
1251
1252 return ret;
1253}
1254
Sujith881ac6a2010-06-01 15:14:11 +05301255static void ath9k_htc_stop(struct ieee80211_hw *hw)
Sujithfb9987d2010-03-17 14:25:25 +05301256{
1257 struct ath9k_htc_priv *priv = hw->priv;
1258 struct ath_hw *ah = priv->ah;
1259 struct ath_common *common = ath9k_hw_common(ah);
1260 int ret = 0;
1261 u8 cmd_rsp;
1262
Sujith881ac6a2010-06-01 15:14:11 +05301263 mutex_lock(&priv->mutex);
1264
Sujithfb9987d2010-03-17 14:25:25 +05301265 if (priv->op_flags & OP_INVALID) {
1266 ath_print(common, ATH_DBG_ANY, "Device not present\n");
Sujith881ac6a2010-06-01 15:14:11 +05301267 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301268 return;
1269 }
1270
Sujith7073daa2010-04-23 10:28:13 +05301271 /* Cancel all the running timers/work .. */
1272 cancel_work_sync(&priv->ps_work);
1273 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1274 cancel_delayed_work_sync(&priv->ath9k_aggr_work);
1275 cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
1276 ath9k_led_stop_brightness(priv);
1277
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301278 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301279 htc_stop(priv->htc);
1280 WMI_CMD(WMI_DISABLE_INTR_CMDID);
1281 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
1282 WMI_CMD(WMI_STOP_RECV_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301283 skb_queue_purge(&priv->tx_queue);
1284
1285 /* Remove monitor interface here */
1286 if (ah->opmode == NL80211_IFTYPE_MONITOR) {
1287 if (ath9k_htc_remove_monitor_interface(priv))
1288 ath_print(common, ATH_DBG_FATAL,
1289 "Unable to remove monitor interface\n");
1290 else
1291 ath_print(common, ATH_DBG_CONFIG,
1292 "Monitor interface removed\n");
1293 }
1294
Sujithe9201f02010-06-01 15:14:17 +05301295 ath9k_hw_phy_disable(ah);
1296 ath9k_hw_disable(ah);
1297 ath9k_hw_configpcipowersave(ah, 1, 1);
1298 ath9k_htc_ps_restore(priv);
1299 ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
1300
Sujithfb9987d2010-03-17 14:25:25 +05301301 priv->op_flags |= OP_INVALID;
Sujithfb9987d2010-03-17 14:25:25 +05301302
1303 ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301304 mutex_unlock(&priv->mutex);
1305}
1306
Sujithfb9987d2010-03-17 14:25:25 +05301307static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
1308 struct ieee80211_vif *vif)
1309{
1310 struct ath9k_htc_priv *priv = hw->priv;
1311 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1312 struct ath_common *common = ath9k_hw_common(priv->ah);
1313 struct ath9k_htc_target_vif hvif;
1314 int ret = 0;
1315 u8 cmd_rsp;
1316
1317 mutex_lock(&priv->mutex);
1318
1319 /* Only one interface for now */
1320 if (priv->nvifs > 0) {
1321 ret = -ENOBUFS;
1322 goto out;
1323 }
1324
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301325 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301326 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1327 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1328
1329 switch (vif->type) {
1330 case NL80211_IFTYPE_STATION:
1331 hvif.opmode = cpu_to_be32(HTC_M_STA);
1332 break;
1333 case NL80211_IFTYPE_ADHOC:
1334 hvif.opmode = cpu_to_be32(HTC_M_IBSS);
1335 break;
1336 default:
1337 ath_print(common, ATH_DBG_FATAL,
1338 "Interface type %d not yet supported\n", vif->type);
1339 ret = -EOPNOTSUPP;
1340 goto out;
1341 }
1342
1343 ath_print(common, ATH_DBG_CONFIG,
1344 "Attach a VIF of type: %d\n", vif->type);
1345
1346 priv->ah->opmode = vif->type;
1347
1348 /* Index starts from zero on the target */
1349 avp->index = hvif.index = priv->nvifs;
1350 hvif.rtsthreshold = cpu_to_be16(2304);
1351 WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
1352 if (ret)
1353 goto out;
1354
1355 priv->nvifs++;
1356
1357 /*
1358 * We need a node in target to tx mgmt frames
1359 * before association.
1360 */
1361 ret = ath9k_htc_add_station(priv, vif, NULL);
1362 if (ret)
1363 goto out;
1364
1365 ret = ath9k_htc_update_cap_target(priv);
1366 if (ret)
1367 ath_print(common, ATH_DBG_CONFIG, "Failed to update"
1368 " capability in target \n");
1369
1370 priv->vif = vif;
1371out:
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301372 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301373 mutex_unlock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301374
Sujithfb9987d2010-03-17 14:25:25 +05301375 return ret;
1376}
1377
1378static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
1379 struct ieee80211_vif *vif)
1380{
1381 struct ath9k_htc_priv *priv = hw->priv;
1382 struct ath_common *common = ath9k_hw_common(priv->ah);
1383 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1384 struct ath9k_htc_target_vif hvif;
1385 int ret = 0;
1386 u8 cmd_rsp;
1387
1388 ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
1389
1390 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301391 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301392
1393 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1394 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1395 hvif.index = avp->index;
1396 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
1397 priv->nvifs--;
1398
1399 ath9k_htc_remove_station(priv, vif, NULL);
Sujithfb9987d2010-03-17 14:25:25 +05301400 priv->vif = NULL;
1401
Sujithcb551df2010-06-01 15:14:12 +05301402 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301403 mutex_unlock(&priv->mutex);
1404}
1405
1406static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
1407{
1408 struct ath9k_htc_priv *priv = hw->priv;
1409 struct ath_common *common = ath9k_hw_common(priv->ah);
1410 struct ieee80211_conf *conf = &hw->conf;
1411
1412 mutex_lock(&priv->mutex);
1413
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301414 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1415 bool enable_radio = false;
1416 bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
1417
Sujith23367762010-06-01 15:14:16 +05301418 mutex_lock(&priv->htc_pm_lock);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301419 if (!idle && priv->ps_idle)
1420 enable_radio = true;
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301421 priv->ps_idle = idle;
Sujith23367762010-06-01 15:14:16 +05301422 mutex_unlock(&priv->htc_pm_lock);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301423
1424 if (enable_radio) {
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301425 ath_print(common, ATH_DBG_CONFIG,
1426 "not-idle: enabling radio\n");
Sujith23367762010-06-01 15:14:16 +05301427 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1428 ath9k_htc_radio_enable(hw);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301429 }
1430 }
1431
Sujithfb9987d2010-03-17 14:25:25 +05301432 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1433 struct ieee80211_channel *curchan = hw->conf.channel;
1434 int pos = curchan->hw_value;
Sujithfb9987d2010-03-17 14:25:25 +05301435
1436 ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
1437 curchan->center_freq);
1438
Sujithfb9987d2010-03-17 14:25:25 +05301439 ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
1440
1441 if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
1442 ath_print(common, ATH_DBG_FATAL,
1443 "Unable to set channel\n");
1444 mutex_unlock(&priv->mutex);
1445 return -EINVAL;
1446 }
1447
1448 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301449 if (changed & IEEE80211_CONF_CHANGE_PS) {
1450 if (conf->flags & IEEE80211_CONF_PS) {
1451 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
1452 priv->ps_enabled = true;
1453 } else {
1454 priv->ps_enabled = false;
1455 cancel_work_sync(&priv->ps_work);
1456 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1457 }
1458 }
Sujithfb9987d2010-03-17 14:25:25 +05301459
1460 if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
1461 if (conf->flags & IEEE80211_CONF_MONITOR) {
1462 if (ath9k_htc_add_monitor_interface(priv))
1463 ath_print(common, ATH_DBG_FATAL,
1464 "Failed to set monitor mode\n");
1465 else
1466 ath_print(common, ATH_DBG_CONFIG,
1467 "HW opmode set to Monitor mode\n");
1468 }
1469 }
1470
Sujith23367762010-06-01 15:14:16 +05301471 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1472 mutex_lock(&priv->htc_pm_lock);
1473 if (!priv->ps_idle) {
1474 mutex_unlock(&priv->htc_pm_lock);
1475 goto out;
1476 }
1477 mutex_unlock(&priv->htc_pm_lock);
1478
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301479 ath_print(common, ATH_DBG_CONFIG,
1480 "idle: disabling radio\n");
Sujith881ac6a2010-06-01 15:14:11 +05301481 ath9k_htc_radio_disable(hw);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301482 }
1483
Sujith23367762010-06-01 15:14:16 +05301484out:
Sujithfb9987d2010-03-17 14:25:25 +05301485 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301486 return 0;
1487}
1488
1489#define SUPPORTED_FILTERS \
1490 (FIF_PROMISC_IN_BSS | \
1491 FIF_ALLMULTI | \
1492 FIF_CONTROL | \
1493 FIF_PSPOLL | \
1494 FIF_OTHER_BSS | \
1495 FIF_BCN_PRBRESP_PROMISC | \
1496 FIF_FCSFAIL)
1497
1498static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
1499 unsigned int changed_flags,
1500 unsigned int *total_flags,
1501 u64 multicast)
1502{
1503 struct ath9k_htc_priv *priv = hw->priv;
1504 u32 rfilt;
1505
1506 mutex_lock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301507 ath9k_htc_ps_wakeup(priv);
Sujithcb551df2010-06-01 15:14:12 +05301508
Sujithfb9987d2010-03-17 14:25:25 +05301509 changed_flags &= SUPPORTED_FILTERS;
1510 *total_flags &= SUPPORTED_FILTERS;
1511
1512 priv->rxfilter = *total_flags;
Sujith0995d112010-03-29 16:07:09 +05301513 rfilt = ath9k_htc_calcrxfilter(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301514 ath9k_hw_setrxfilter(priv->ah, rfilt);
1515
1516 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
1517 "Set HW RX filter: 0x%x\n", rfilt);
1518
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301519 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301520 mutex_unlock(&priv->mutex);
1521}
1522
Sujithabd984e2010-05-18 15:26:04 +05301523static int ath9k_htc_sta_add(struct ieee80211_hw *hw,
1524 struct ieee80211_vif *vif,
1525 struct ieee80211_sta *sta)
Sujithfb9987d2010-03-17 14:25:25 +05301526{
1527 struct ath9k_htc_priv *priv = hw->priv;
1528 int ret;
1529
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301530 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301531 ath9k_htc_ps_wakeup(priv);
Sujithabd984e2010-05-18 15:26:04 +05301532 ret = ath9k_htc_add_station(priv, vif, sta);
1533 if (!ret)
1534 ath9k_htc_init_rate(priv, sta);
Sujithcb551df2010-06-01 15:14:12 +05301535 ath9k_htc_ps_restore(priv);
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301536 mutex_unlock(&priv->mutex);
Sujithabd984e2010-05-18 15:26:04 +05301537
1538 return ret;
1539}
1540
1541static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
1542 struct ieee80211_vif *vif,
1543 struct ieee80211_sta *sta)
1544{
1545 struct ath9k_htc_priv *priv = hw->priv;
1546 int ret;
1547
1548 mutex_lock(&priv->mutex);
1549 ath9k_htc_ps_wakeup(priv);
1550 ret = ath9k_htc_remove_station(priv, vif, sta);
1551 ath9k_htc_ps_restore(priv);
1552 mutex_unlock(&priv->mutex);
1553
1554 return ret;
Sujithfb9987d2010-03-17 14:25:25 +05301555}
1556
1557static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
1558 const struct ieee80211_tx_queue_params *params)
1559{
1560 struct ath9k_htc_priv *priv = hw->priv;
1561 struct ath_common *common = ath9k_hw_common(priv->ah);
1562 struct ath9k_tx_queue_info qi;
1563 int ret = 0, qnum;
1564
1565 if (queue >= WME_NUM_AC)
1566 return 0;
1567
1568 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301569 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301570
1571 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
1572
1573 qi.tqi_aifs = params->aifs;
1574 qi.tqi_cwmin = params->cw_min;
1575 qi.tqi_cwmax = params->cw_max;
1576 qi.tqi_burstTime = params->txop;
1577
1578 qnum = get_hw_qnum(queue, priv->hwq_map);
1579
1580 ath_print(common, ATH_DBG_CONFIG,
1581 "Configure tx [queue/hwq] [%d/%d], "
1582 "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
1583 queue, qnum, params->aifs, params->cw_min,
1584 params->cw_max, params->txop);
1585
Sujithe1572c52010-03-24 13:42:13 +05301586 ret = ath_htc_txq_update(priv, qnum, &qi);
Sujith764580f2010-06-01 15:14:19 +05301587 if (ret) {
Sujithfb9987d2010-03-17 14:25:25 +05301588 ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
Sujith764580f2010-06-01 15:14:19 +05301589 goto out;
1590 }
Sujithfb9987d2010-03-17 14:25:25 +05301591
Sujith764580f2010-06-01 15:14:19 +05301592 if ((priv->ah->opmode == NL80211_IFTYPE_ADHOC) &&
Felix Fietkaue8c35a72010-06-12 00:33:50 -04001593 (qnum == priv->hwq_map[WME_AC_BE]))
Sujith764580f2010-06-01 15:14:19 +05301594 ath9k_htc_beaconq_config(priv);
1595out:
Sujithcb551df2010-06-01 15:14:12 +05301596 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301597 mutex_unlock(&priv->mutex);
1598
1599 return ret;
1600}
1601
1602static int ath9k_htc_set_key(struct ieee80211_hw *hw,
1603 enum set_key_cmd cmd,
1604 struct ieee80211_vif *vif,
1605 struct ieee80211_sta *sta,
1606 struct ieee80211_key_conf *key)
1607{
1608 struct ath9k_htc_priv *priv = hw->priv;
1609 struct ath_common *common = ath9k_hw_common(priv->ah);
1610 int ret = 0;
1611
Sujithe1572c52010-03-24 13:42:13 +05301612 if (htc_modparam_nohwcrypt)
Sujithfb9987d2010-03-17 14:25:25 +05301613 return -ENOSPC;
1614
1615 mutex_lock(&priv->mutex);
1616 ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301617 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301618
1619 switch (cmd) {
1620 case SET_KEY:
1621 ret = ath9k_cmn_key_config(common, vif, sta, key);
1622 if (ret >= 0) {
1623 key->hw_key_idx = ret;
1624 /* push IV and Michael MIC generation to stack */
1625 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
1626 if (key->alg == ALG_TKIP)
1627 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
1628 if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
1629 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
1630 ret = 0;
1631 }
1632 break;
1633 case DISABLE_KEY:
1634 ath9k_cmn_key_delete(common, key);
1635 break;
1636 default:
1637 ret = -EINVAL;
1638 }
1639
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301640 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301641 mutex_unlock(&priv->mutex);
1642
1643 return ret;
1644}
1645
1646static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
1647 struct ieee80211_vif *vif,
1648 struct ieee80211_bss_conf *bss_conf,
1649 u32 changed)
1650{
1651 struct ath9k_htc_priv *priv = hw->priv;
1652 struct ath_hw *ah = priv->ah;
1653 struct ath_common *common = ath9k_hw_common(ah);
1654
1655 mutex_lock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301656 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301657
1658 if (changed & BSS_CHANGED_ASSOC) {
1659 common->curaid = bss_conf->assoc ?
1660 bss_conf->aid : 0;
1661 ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
1662 bss_conf->assoc);
1663
1664 if (bss_conf->assoc) {
1665 priv->op_flags |= OP_ASSOCIATED;
1666 ath_start_ani(priv);
1667 } else {
1668 priv->op_flags &= ~OP_ASSOCIATED;
1669 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1670 }
1671 }
1672
1673 if (changed & BSS_CHANGED_BSSID) {
1674 /* Set BSSID */
1675 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1676 ath9k_hw_write_associd(ah);
1677
1678 ath_print(common, ATH_DBG_CONFIG,
1679 "BSSID: %pM aid: 0x%x\n",
1680 common->curbssid, common->curaid);
1681 }
1682
1683 if ((changed & BSS_CHANGED_BEACON_INT) ||
1684 (changed & BSS_CHANGED_BEACON) ||
1685 ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1686 bss_conf->enable_beacon)) {
1687 priv->op_flags |= OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301688 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301689 }
1690
Sujithfb9987d2010-03-17 14:25:25 +05301691 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1692 !bss_conf->enable_beacon) {
1693 priv->op_flags &= ~OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301694 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301695 }
1696
1697 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1698 ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
1699 bss_conf->use_short_preamble);
1700 if (bss_conf->use_short_preamble)
1701 priv->op_flags |= OP_PREAMBLE_SHORT;
1702 else
1703 priv->op_flags &= ~OP_PREAMBLE_SHORT;
1704 }
1705
1706 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1707 ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
1708 bss_conf->use_cts_prot);
1709 if (bss_conf->use_cts_prot &&
1710 hw->conf.channel->band != IEEE80211_BAND_5GHZ)
1711 priv->op_flags |= OP_PROTECT_ENABLE;
1712 else
1713 priv->op_flags &= ~OP_PROTECT_ENABLE;
1714 }
1715
1716 if (changed & BSS_CHANGED_ERP_SLOT) {
1717 if (bss_conf->use_short_slot)
1718 ah->slottime = 9;
1719 else
1720 ah->slottime = 20;
1721
1722 ath9k_hw_init_global_settings(ah);
1723 }
1724
Sujith2c76ef82010-05-17 12:01:18 +05301725 if (changed & BSS_CHANGED_HT)
1726 ath9k_htc_update_rate(priv, vif, bss_conf);
1727
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301728 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301729 mutex_unlock(&priv->mutex);
1730}
1731
1732static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
1733{
1734 struct ath9k_htc_priv *priv = hw->priv;
1735 u64 tsf;
1736
1737 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301738 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301739 tsf = ath9k_hw_gettsf64(priv->ah);
Sujithcb551df2010-06-01 15:14:12 +05301740 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301741 mutex_unlock(&priv->mutex);
1742
1743 return tsf;
1744}
1745
1746static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
1747{
1748 struct ath9k_htc_priv *priv = hw->priv;
1749
1750 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301751 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301752 ath9k_hw_settsf64(priv->ah, tsf);
Sujithcb551df2010-06-01 15:14:12 +05301753 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301754 mutex_unlock(&priv->mutex);
1755}
1756
1757static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
1758{
1759 struct ath9k_htc_priv *priv = hw->priv;
1760
1761 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301762 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301763 ath9k_hw_reset_tsf(priv->ah);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301764 ath9k_htc_ps_restore(priv);
Sujithcb551df2010-06-01 15:14:12 +05301765 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301766}
1767
1768static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
1769 struct ieee80211_vif *vif,
1770 enum ieee80211_ampdu_mlme_action action,
1771 struct ieee80211_sta *sta,
1772 u16 tid, u16 *ssn)
1773{
1774 struct ath9k_htc_priv *priv = hw->priv;
1775 struct ath9k_htc_aggr_work *work = &priv->aggr_work;
1776 struct ath9k_htc_sta *ista;
1777
1778 switch (action) {
1779 case IEEE80211_AMPDU_RX_START:
1780 break;
1781 case IEEE80211_AMPDU_RX_STOP:
1782 break;
1783 case IEEE80211_AMPDU_TX_START:
1784 case IEEE80211_AMPDU_TX_STOP:
1785 if (!(priv->op_flags & OP_TXAGGR))
1786 return -ENOTSUPP;
1787 memcpy(work->sta_addr, sta->addr, ETH_ALEN);
1788 work->hw = hw;
1789 work->vif = vif;
1790 work->action = action;
1791 work->tid = tid;
1792 ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0);
1793 break;
1794 case IEEE80211_AMPDU_TX_OPERATIONAL:
1795 ista = (struct ath9k_htc_sta *) sta->drv_priv;
1796 ista->tid_state[tid] = AGGR_OPERATIONAL;
1797 break;
1798 default:
1799 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
1800 "Unknown AMPDU action\n");
1801 }
1802
1803 return 0;
1804}
1805
1806static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
1807{
1808 struct ath9k_htc_priv *priv = hw->priv;
1809
1810 mutex_lock(&priv->mutex);
1811 spin_lock_bh(&priv->beacon_lock);
1812 priv->op_flags |= OP_SCANNING;
1813 spin_unlock_bh(&priv->beacon_lock);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301814 cancel_work_sync(&priv->ps_work);
Sujithfb9987d2010-03-17 14:25:25 +05301815 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1816 mutex_unlock(&priv->mutex);
1817}
1818
1819static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
1820{
1821 struct ath9k_htc_priv *priv = hw->priv;
1822
1823 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301824 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301825 spin_lock_bh(&priv->beacon_lock);
1826 priv->op_flags &= ~OP_SCANNING;
1827 spin_unlock_bh(&priv->beacon_lock);
1828 priv->op_flags |= OP_FULL_RESET;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301829 if (priv->op_flags & OP_ASSOCIATED)
Sujithfcb93922010-04-16 11:53:48 +05301830 ath9k_htc_beacon_config(priv, priv->vif);
Sujithfb9987d2010-03-17 14:25:25 +05301831 ath_start_ani(priv);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301832 ath9k_htc_ps_restore(priv);
Sujithcb551df2010-06-01 15:14:12 +05301833 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301834}
1835
1836static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1837{
1838 return 0;
1839}
1840
1841static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
1842 u8 coverage_class)
1843{
1844 struct ath9k_htc_priv *priv = hw->priv;
1845
1846 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301847 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301848 priv->ah->coverage_class = coverage_class;
1849 ath9k_hw_init_global_settings(priv->ah);
Sujithcb551df2010-06-01 15:14:12 +05301850 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301851 mutex_unlock(&priv->mutex);
1852}
1853
1854struct ieee80211_ops ath9k_htc_ops = {
1855 .tx = ath9k_htc_tx,
1856 .start = ath9k_htc_start,
1857 .stop = ath9k_htc_stop,
1858 .add_interface = ath9k_htc_add_interface,
1859 .remove_interface = ath9k_htc_remove_interface,
1860 .config = ath9k_htc_config,
1861 .configure_filter = ath9k_htc_configure_filter,
Sujithabd984e2010-05-18 15:26:04 +05301862 .sta_add = ath9k_htc_sta_add,
1863 .sta_remove = ath9k_htc_sta_remove,
Sujithfb9987d2010-03-17 14:25:25 +05301864 .conf_tx = ath9k_htc_conf_tx,
1865 .bss_info_changed = ath9k_htc_bss_info_changed,
1866 .set_key = ath9k_htc_set_key,
1867 .get_tsf = ath9k_htc_get_tsf,
1868 .set_tsf = ath9k_htc_set_tsf,
1869 .reset_tsf = ath9k_htc_reset_tsf,
1870 .ampdu_action = ath9k_htc_ampdu_action,
1871 .sw_scan_start = ath9k_htc_sw_scan_start,
1872 .sw_scan_complete = ath9k_htc_sw_scan_complete,
1873 .set_rts_threshold = ath9k_htc_set_rts_threshold,
1874 .rfkill_poll = ath9k_htc_rfkill_poll_state,
1875 .set_coverage_class = ath9k_htc_set_coverage_class,
1876};