blob: 05445d8a9818111c03de6295fce43b0789cdb556 [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;
Sujithfb9987d2010-03-17 14:25:25 +053030
31 if (priv->curtxpow != priv->txpowlimit) {
32 ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit);
33 /* read back in case value is clamped */
Felix Fietkau9cc32712010-06-12 17:22:29 +020034 priv->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
Sujithfb9987d2010-03-17 14:25:25 +053035 }
36}
37
38/* HACK Alert: Use 11NG for 2.4, use 11NA for 5 */
39static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
40 struct ath9k_channel *ichan)
41{
42 enum htc_phymode mode;
43
44 mode = HTC_MODE_AUTO;
45
46 switch (ichan->chanmode) {
47 case CHANNEL_G:
48 case CHANNEL_G_HT20:
49 case CHANNEL_G_HT40PLUS:
50 case CHANNEL_G_HT40MINUS:
51 mode = HTC_MODE_11NG;
52 break;
53 case CHANNEL_A:
54 case CHANNEL_A_HT20:
55 case CHANNEL_A_HT40PLUS:
56 case CHANNEL_A_HT40MINUS:
57 mode = HTC_MODE_11NA;
58 break;
59 default:
60 break;
61 }
62
63 return mode;
64}
65
Vivek Natarajanbde748a2010-04-05 14:48:05 +053066static bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
67 enum ath9k_power_mode mode)
68{
69 bool ret;
70
71 mutex_lock(&priv->htc_pm_lock);
72 ret = ath9k_hw_setpower(priv->ah, mode);
73 mutex_unlock(&priv->htc_pm_lock);
74
75 return ret;
76}
77
78void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv)
79{
80 mutex_lock(&priv->htc_pm_lock);
81 if (++priv->ps_usecount != 1)
82 goto unlock;
83 ath9k_hw_setpower(priv->ah, ATH9K_PM_AWAKE);
84
85unlock:
86 mutex_unlock(&priv->htc_pm_lock);
87}
88
89void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv)
90{
91 mutex_lock(&priv->htc_pm_lock);
92 if (--priv->ps_usecount != 0)
93 goto unlock;
94
Vivek Natarajan8a8572a2010-04-27 13:05:37 +053095 if (priv->ps_idle)
96 ath9k_hw_setpower(priv->ah, ATH9K_PM_FULL_SLEEP);
97 else if (priv->ps_enabled)
Vivek Natarajanbde748a2010-04-05 14:48:05 +053098 ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +053099
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530100unlock:
101 mutex_unlock(&priv->htc_pm_lock);
102}
103
104void ath9k_ps_work(struct work_struct *work)
105{
106 struct ath9k_htc_priv *priv =
107 container_of(work, struct ath9k_htc_priv,
108 ps_work);
109 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
110
111 /* The chip wakes up after receiving the first beacon
112 while network sleep is enabled. For the driver to
113 be in sync with the hw, set the chip to awake and
114 only then set it to sleep.
115 */
116 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
117}
118
Sujithfb9987d2010-03-17 14:25:25 +0530119static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
120 struct ieee80211_hw *hw,
121 struct ath9k_channel *hchan)
122{
123 struct ath_hw *ah = priv->ah;
124 struct ath_common *common = ath9k_hw_common(ah);
125 struct ieee80211_conf *conf = &common->hw->conf;
126 bool fastcc = true;
127 struct ieee80211_channel *channel = hw->conf.channel;
128 enum htc_phymode mode;
Sujith7f1f5a02010-04-16 11:54:03 +0530129 __be16 htc_mode;
Sujithfb9987d2010-03-17 14:25:25 +0530130 u8 cmd_rsp;
131 int ret;
132
133 if (priv->op_flags & OP_INVALID)
134 return -EIO;
135
136 if (priv->op_flags & OP_FULL_RESET)
137 fastcc = false;
138
139 /* Fiddle around with fastcc later on, for now just use full reset */
140 fastcc = false;
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530141 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530142 htc_stop(priv->htc);
143 WMI_CMD(WMI_DISABLE_INTR_CMDID);
144 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
145 WMI_CMD(WMI_STOP_RECV_CMDID);
146
147 ath_print(common, ATH_DBG_CONFIG,
148 "(%u MHz) -> (%u MHz), HT: %d, HT40: %d\n",
149 priv->ah->curchan->channel,
150 channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf));
151
152 ret = ath9k_hw_reset(ah, hchan, fastcc);
153 if (ret) {
154 ath_print(common, ATH_DBG_FATAL,
155 "Unable to reset channel (%u Mhz) "
156 "reset status %d\n", channel->center_freq, ret);
157 goto err;
158 }
159
160 ath_update_txpow(priv);
161
162 WMI_CMD(WMI_START_RECV_CMDID);
163 if (ret)
164 goto err;
165
166 ath9k_host_rx_init(priv);
167
168 mode = ath9k_htc_get_curmode(priv, hchan);
169 htc_mode = cpu_to_be16(mode);
170 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
171 if (ret)
172 goto err;
173
174 WMI_CMD(WMI_ENABLE_INTR_CMDID);
175 if (ret)
176 goto err;
177
178 htc_start(priv->htc);
179
180 priv->op_flags &= ~OP_FULL_RESET;
181err:
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530182 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530183 return ret;
184}
185
186static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
187{
188 struct ath_common *common = ath9k_hw_common(priv->ah);
189 struct ath9k_htc_target_vif hvif;
190 int ret = 0;
191 u8 cmd_rsp;
192
193 if (priv->nvifs > 0)
194 return -ENOBUFS;
195
196 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
197 memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
198
199 hvif.opmode = cpu_to_be32(HTC_M_MONITOR);
200 priv->ah->opmode = NL80211_IFTYPE_MONITOR;
201 hvif.index = priv->nvifs;
202
203 WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
204 if (ret)
205 return ret;
206
207 priv->nvifs++;
208 return 0;
209}
210
211static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
212{
213 struct ath_common *common = ath9k_hw_common(priv->ah);
214 struct ath9k_htc_target_vif hvif;
215 int ret = 0;
216 u8 cmd_rsp;
217
218 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
219 memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
220 hvif.index = 0; /* Should do for now */
221 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
222 priv->nvifs--;
223
224 return ret;
225}
226
227static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
228 struct ieee80211_vif *vif,
229 struct ieee80211_sta *sta)
230{
231 struct ath_common *common = ath9k_hw_common(priv->ah);
232 struct ath9k_htc_target_sta tsta;
233 struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
234 struct ath9k_htc_sta *ista;
235 int ret;
236 u8 cmd_rsp;
237
238 if (priv->nstations >= ATH9K_HTC_MAX_STA)
239 return -ENOBUFS;
240
241 memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta));
242
243 if (sta) {
244 ista = (struct ath9k_htc_sta *) sta->drv_priv;
245 memcpy(&tsta.macaddr, sta->addr, ETH_ALEN);
246 memcpy(&tsta.bssid, common->curbssid, ETH_ALEN);
247 tsta.associd = common->curaid;
248 tsta.is_vif_sta = 0;
249 tsta.valid = true;
250 ista->index = priv->nstations;
251 } else {
252 memcpy(&tsta.macaddr, vif->addr, ETH_ALEN);
253 tsta.is_vif_sta = 1;
254 }
255
256 tsta.sta_index = priv->nstations;
257 tsta.vif_index = avp->index;
258 tsta.maxampdu = 0xffff;
259 if (sta && sta->ht_cap.ht_supported)
260 tsta.flags = cpu_to_be16(ATH_HTC_STA_HT);
261
262 WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
263 if (ret) {
264 if (sta)
265 ath_print(common, ATH_DBG_FATAL,
266 "Unable to add station entry for: %pM\n", sta->addr);
267 return ret;
268 }
269
270 if (sta)
271 ath_print(common, ATH_DBG_CONFIG,
272 "Added a station entry for: %pM (idx: %d)\n",
273 sta->addr, tsta.sta_index);
274
275 priv->nstations++;
276 return 0;
277}
278
279static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
280 struct ieee80211_vif *vif,
281 struct ieee80211_sta *sta)
282{
283 struct ath_common *common = ath9k_hw_common(priv->ah);
284 struct ath9k_htc_sta *ista;
285 int ret;
286 u8 cmd_rsp, sta_idx;
287
288 if (sta) {
289 ista = (struct ath9k_htc_sta *) sta->drv_priv;
290 sta_idx = ista->index;
291 } else {
292 sta_idx = 0;
293 }
294
295 WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx);
296 if (ret) {
297 if (sta)
298 ath_print(common, ATH_DBG_FATAL,
299 "Unable to remove station entry for: %pM\n",
300 sta->addr);
301 return ret;
302 }
303
304 if (sta)
305 ath_print(common, ATH_DBG_CONFIG,
306 "Removed a station entry for: %pM (idx: %d)\n",
307 sta->addr, sta_idx);
308
309 priv->nstations--;
310 return 0;
311}
312
313static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
314{
315 struct ath9k_htc_cap_target tcap;
316 int ret;
317 u8 cmd_rsp;
318
319 memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target));
320
321 /* FIXME: Values are hardcoded */
322 tcap.flags = 0x240c40;
323 tcap.flags_ext = 0x80601000;
324 tcap.ampdu_limit = 0xffff0000;
325 tcap.ampdu_subframes = 20;
Sujith29d90752010-06-02 15:53:43 +0530326 tcap.tx_chainmask_legacy = priv->ah->caps.tx_chainmask;
Sujithfb9987d2010-03-17 14:25:25 +0530327 tcap.protmode = 1;
Sujith29d90752010-06-02 15:53:43 +0530328 tcap.tx_chainmask = priv->ah->caps.tx_chainmask;
Sujithfb9987d2010-03-17 14:25:25 +0530329
330 WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap);
331
332 return ret;
333}
334
Sujith0d425a72010-05-17 12:01:16 +0530335static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv,
336 struct ieee80211_sta *sta,
337 struct ath9k_htc_target_rate *trate)
Sujithfb9987d2010-03-17 14:25:25 +0530338{
Sujithfb9987d2010-03-17 14:25:25 +0530339 struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
340 struct ieee80211_supported_band *sband;
Sujithfb9987d2010-03-17 14:25:25 +0530341 u32 caps = 0;
Sujith0d425a72010-05-17 12:01:16 +0530342 int i, j;
Sujithfb9987d2010-03-17 14:25:25 +0530343
Sujithea46e642010-06-02 15:53:50 +0530344 sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band];
Sujithfb9987d2010-03-17 14:25:25 +0530345
346 for (i = 0, j = 0; i < sband->n_bitrates; i++) {
347 if (sta->supp_rates[sband->band] & BIT(i)) {
Sujith0d425a72010-05-17 12:01:16 +0530348 trate->rates.legacy_rates.rs_rates[j]
Sujithfb9987d2010-03-17 14:25:25 +0530349 = (sband->bitrates[i].bitrate * 2) / 10;
350 j++;
351 }
352 }
Sujith0d425a72010-05-17 12:01:16 +0530353 trate->rates.legacy_rates.rs_nrates = j;
Sujithfb9987d2010-03-17 14:25:25 +0530354
355 if (sta->ht_cap.ht_supported) {
356 for (i = 0, j = 0; i < 77; i++) {
357 if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
Sujith0d425a72010-05-17 12:01:16 +0530358 trate->rates.ht_rates.rs_rates[j++] = i;
Sujithfb9987d2010-03-17 14:25:25 +0530359 if (j == ATH_HTC_RATE_MAX)
360 break;
361 }
Sujith0d425a72010-05-17 12:01:16 +0530362 trate->rates.ht_rates.rs_nrates = j;
Sujithfb9987d2010-03-17 14:25:25 +0530363
364 caps = WLAN_RC_HT_FLAG;
Felix Fietkau35537272010-06-12 17:22:33 +0200365 if (sta->ht_cap.mcs.rx_mask[1])
366 caps |= WLAN_RC_DS_FLAG;
Sujithfb9987d2010-03-17 14:25:25 +0530367 if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
368 caps |= WLAN_RC_40_FLAG;
Sujithb4dec5e2010-05-17 12:01:19 +0530369 if (conf_is_ht40(&priv->hw->conf) &&
370 (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40))
Sujithfb9987d2010-03-17 14:25:25 +0530371 caps |= WLAN_RC_SGI_FLAG;
Sujithb4dec5e2010-05-17 12:01:19 +0530372 else if (conf_is_ht20(&priv->hw->conf) &&
373 (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20))
374 caps |= WLAN_RC_SGI_FLAG;
Sujithfb9987d2010-03-17 14:25:25 +0530375 }
376
Sujith0d425a72010-05-17 12:01:16 +0530377 trate->sta_index = ista->index;
378 trate->isnew = 1;
379 trate->capflags = cpu_to_be32(caps);
380}
Sujithfb9987d2010-03-17 14:25:25 +0530381
Sujith0d425a72010-05-17 12:01:16 +0530382static int ath9k_htc_send_rate_cmd(struct ath9k_htc_priv *priv,
383 struct ath9k_htc_target_rate *trate)
384{
385 struct ath_common *common = ath9k_hw_common(priv->ah);
386 int ret;
387 u8 cmd_rsp;
388
389 WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, trate);
Sujithfb9987d2010-03-17 14:25:25 +0530390 if (ret) {
391 ath_print(common, ATH_DBG_FATAL,
392 "Unable to initialize Rate information on target\n");
Sujithfb9987d2010-03-17 14:25:25 +0530393 }
394
Sujith0d425a72010-05-17 12:01:16 +0530395 return ret;
Sujithfb9987d2010-03-17 14:25:25 +0530396}
397
Sujith0d425a72010-05-17 12:01:16 +0530398static void ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
399 struct ieee80211_sta *sta)
Sujithfb9987d2010-03-17 14:25:25 +0530400{
Sujithfb9987d2010-03-17 14:25:25 +0530401 struct ath_common *common = ath9k_hw_common(priv->ah);
Sujith0d425a72010-05-17 12:01:16 +0530402 struct ath9k_htc_target_rate trate;
Sujithfb9987d2010-03-17 14:25:25 +0530403 int ret;
Sujithfb9987d2010-03-17 14:25:25 +0530404
Sujith0d425a72010-05-17 12:01:16 +0530405 memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
406 ath9k_htc_setup_rate(priv, sta, &trate);
407 ret = ath9k_htc_send_rate_cmd(priv, &trate);
408 if (!ret)
409 ath_print(common, ATH_DBG_CONFIG,
410 "Updated target sta: %pM, rate caps: 0x%X\n",
411 sta->addr, be32_to_cpu(trate.capflags));
Sujithfb9987d2010-03-17 14:25:25 +0530412}
413
Sujith2c76ef82010-05-17 12:01:18 +0530414static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv,
415 struct ieee80211_vif *vif,
416 struct ieee80211_bss_conf *bss_conf)
417{
418 struct ath_common *common = ath9k_hw_common(priv->ah);
419 struct ath9k_htc_target_rate trate;
420 struct ieee80211_sta *sta;
421 int ret;
422
423 memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
424
425 rcu_read_lock();
426 sta = ieee80211_find_sta(vif, bss_conf->bssid);
427 if (!sta) {
428 rcu_read_unlock();
429 return;
430 }
431 ath9k_htc_setup_rate(priv, sta, &trate);
432 rcu_read_unlock();
433
434 ret = ath9k_htc_send_rate_cmd(priv, &trate);
435 if (!ret)
436 ath_print(common, ATH_DBG_CONFIG,
437 "Updated target sta: %pM, rate caps: 0x%X\n",
438 bss_conf->bssid, be32_to_cpu(trate.capflags));
439}
440
Sujithd7ca2132010-06-15 10:24:37 +0530441int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv,
442 struct ieee80211_vif *vif,
443 struct ieee80211_sta *sta,
444 enum ieee80211_ampdu_mlme_action action, u16 tid)
Sujithfb9987d2010-03-17 14:25:25 +0530445{
446 struct ath_common *common = ath9k_hw_common(priv->ah);
447 struct ath9k_htc_target_aggr aggr;
Dan Carpenter277a64d2010-05-08 18:23:20 +0200448 struct ath9k_htc_sta *ista;
Sujithfb9987d2010-03-17 14:25:25 +0530449 int ret = 0;
450 u8 cmd_rsp;
451
Dan Carpenter0730d112010-05-08 18:24:02 +0200452 if (tid >= ATH9K_HTC_MAX_TID)
Sujithfb9987d2010-03-17 14:25:25 +0530453 return -EINVAL;
454
Sujithfb9987d2010-03-17 14:25:25 +0530455 memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
Sujithef98c3c2010-03-29 16:07:11 +0530456 ista = (struct ath9k_htc_sta *) sta->drv_priv;
Sujithfb9987d2010-03-17 14:25:25 +0530457
Sujithef98c3c2010-03-29 16:07:11 +0530458 aggr.sta_index = ista->index;
Sujithd7ca2132010-06-15 10:24:37 +0530459 aggr.tidno = tid & 0xf;
460 aggr.aggr_enable = (action == IEEE80211_AMPDU_TX_START) ? true : false;
Sujithef98c3c2010-03-29 16:07:11 +0530461
Sujithfb9987d2010-03-17 14:25:25 +0530462 WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
463 if (ret)
464 ath_print(common, ATH_DBG_CONFIG,
465 "Unable to %s TX aggregation for (%pM, %d)\n",
Sujithd7ca2132010-06-15 10:24:37 +0530466 (aggr.aggr_enable) ? "start" : "stop", sta->addr, tid);
Sujithfb9987d2010-03-17 14:25:25 +0530467 else
468 ath_print(common, ATH_DBG_CONFIG,
Sujithd7ca2132010-06-15 10:24:37 +0530469 "%s TX aggregation for (%pM, %d)\n",
470 (aggr.aggr_enable) ? "Starting" : "Stopping",
471 sta->addr, tid);
472
473 spin_lock_bh(&priv->tx_lock);
474 ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
475 spin_unlock_bh(&priv->tx_lock);
Sujithfb9987d2010-03-17 14:25:25 +0530476
477 return ret;
478}
479
Sujithfb9987d2010-03-17 14:25:25 +0530480/*********/
481/* DEBUG */
482/*********/
483
484#ifdef CONFIG_ATH9K_HTC_DEBUGFS
485
486static int ath9k_debugfs_open(struct inode *inode, struct file *file)
487{
488 file->private_data = inode->i_private;
489 return 0;
490}
491
492static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
493 size_t count, loff_t *ppos)
494{
495 struct ath9k_htc_priv *priv =
496 (struct ath9k_htc_priv *) file->private_data;
497 struct ath9k_htc_target_stats cmd_rsp;
498 char buf[512];
499 unsigned int len = 0;
500 int ret = 0;
501
502 memset(&cmd_rsp, 0, sizeof(cmd_rsp));
503
504 WMI_CMD(WMI_TGT_STATS_CMDID);
505 if (ret)
506 return -EINVAL;
507
508
509 len += snprintf(buf + len, sizeof(buf) - len,
510 "%19s : %10u\n", "TX Short Retries",
511 be32_to_cpu(cmd_rsp.tx_shortretry));
512 len += snprintf(buf + len, sizeof(buf) - len,
513 "%19s : %10u\n", "TX Long Retries",
514 be32_to_cpu(cmd_rsp.tx_longretry));
515 len += snprintf(buf + len, sizeof(buf) - len,
516 "%19s : %10u\n", "TX Xretries",
517 be32_to_cpu(cmd_rsp.tx_xretries));
518 len += snprintf(buf + len, sizeof(buf) - len,
519 "%19s : %10u\n", "TX Unaggr. Xretries",
520 be32_to_cpu(cmd_rsp.ht_txunaggr_xretry));
521 len += snprintf(buf + len, sizeof(buf) - len,
522 "%19s : %10u\n", "TX Xretries (HT)",
523 be32_to_cpu(cmd_rsp.ht_tx_xretries));
524 len += snprintf(buf + len, sizeof(buf) - len,
525 "%19s : %10u\n", "TX Rate", priv->debug.txrate);
526
527 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
528}
529
530static const struct file_operations fops_tgt_stats = {
531 .read = read_file_tgt_stats,
532 .open = ath9k_debugfs_open,
533 .owner = THIS_MODULE
534};
535
536static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
537 size_t count, loff_t *ppos)
538{
539 struct ath9k_htc_priv *priv =
540 (struct ath9k_htc_priv *) file->private_data;
541 char buf[512];
542 unsigned int len = 0;
543
544 len += snprintf(buf + len, sizeof(buf) - len,
545 "%20s : %10u\n", "Buffers queued",
546 priv->debug.tx_stats.buf_queued);
547 len += snprintf(buf + len, sizeof(buf) - len,
548 "%20s : %10u\n", "Buffers completed",
549 priv->debug.tx_stats.buf_completed);
550 len += snprintf(buf + len, sizeof(buf) - len,
551 "%20s : %10u\n", "SKBs queued",
552 priv->debug.tx_stats.skb_queued);
553 len += snprintf(buf + len, sizeof(buf) - len,
554 "%20s : %10u\n", "SKBs completed",
555 priv->debug.tx_stats.skb_completed);
Sujitheac8e382010-04-16 11:54:00 +0530556 len += snprintf(buf + len, sizeof(buf) - len,
557 "%20s : %10u\n", "SKBs dropped",
558 priv->debug.tx_stats.skb_dropped);
Sujithfb9987d2010-03-17 14:25:25 +0530559
Sujith2edb4582010-05-14 11:18:54 +0530560 len += snprintf(buf + len, sizeof(buf) - len,
561 "%20s : %10u\n", "BE queued",
562 priv->debug.tx_stats.queue_stats[WME_AC_BE]);
563 len += snprintf(buf + len, sizeof(buf) - len,
564 "%20s : %10u\n", "BK queued",
565 priv->debug.tx_stats.queue_stats[WME_AC_BK]);
566 len += snprintf(buf + len, sizeof(buf) - len,
567 "%20s : %10u\n", "VI queued",
568 priv->debug.tx_stats.queue_stats[WME_AC_VI]);
569 len += snprintf(buf + len, sizeof(buf) - len,
570 "%20s : %10u\n", "VO queued",
571 priv->debug.tx_stats.queue_stats[WME_AC_VO]);
572
Sujithfb9987d2010-03-17 14:25:25 +0530573 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
574}
575
576static const struct file_operations fops_xmit = {
577 .read = read_file_xmit,
578 .open = ath9k_debugfs_open,
579 .owner = THIS_MODULE
580};
581
582static ssize_t read_file_recv(struct file *file, char __user *user_buf,
583 size_t count, loff_t *ppos)
584{
585 struct ath9k_htc_priv *priv =
586 (struct ath9k_htc_priv *) file->private_data;
587 char buf[512];
588 unsigned int len = 0;
589
590 len += snprintf(buf + len, sizeof(buf) - len,
591 "%20s : %10u\n", "SKBs allocated",
592 priv->debug.rx_stats.skb_allocated);
593 len += snprintf(buf + len, sizeof(buf) - len,
594 "%20s : %10u\n", "SKBs completed",
595 priv->debug.rx_stats.skb_completed);
596 len += snprintf(buf + len, sizeof(buf) - len,
597 "%20s : %10u\n", "SKBs Dropped",
598 priv->debug.rx_stats.skb_dropped);
599
600 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
601}
602
603static const struct file_operations fops_recv = {
604 .read = read_file_recv,
605 .open = ath9k_debugfs_open,
606 .owner = THIS_MODULE
607};
608
Sujithe1572c52010-03-24 13:42:13 +0530609int ath9k_htc_init_debug(struct ath_hw *ah)
Sujithfb9987d2010-03-17 14:25:25 +0530610{
611 struct ath_common *common = ath9k_hw_common(ah);
612 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
613
614 if (!ath9k_debugfs_root)
615 return -ENOENT;
616
617 priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy),
618 ath9k_debugfs_root);
619 if (!priv->debug.debugfs_phy)
620 goto err;
621
622 priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR,
623 priv->debug.debugfs_phy,
624 priv, &fops_tgt_stats);
625 if (!priv->debug.debugfs_tgt_stats)
626 goto err;
627
628
629 priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR,
630 priv->debug.debugfs_phy,
631 priv, &fops_xmit);
632 if (!priv->debug.debugfs_xmit)
633 goto err;
634
635 priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR,
636 priv->debug.debugfs_phy,
637 priv, &fops_recv);
638 if (!priv->debug.debugfs_recv)
639 goto err;
640
641 return 0;
642
643err:
Sujithe1572c52010-03-24 13:42:13 +0530644 ath9k_htc_exit_debug(ah);
Sujithfb9987d2010-03-17 14:25:25 +0530645 return -ENOMEM;
646}
647
Sujithe1572c52010-03-24 13:42:13 +0530648void ath9k_htc_exit_debug(struct ath_hw *ah)
Sujithfb9987d2010-03-17 14:25:25 +0530649{
650 struct ath_common *common = ath9k_hw_common(ah);
651 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
652
653 debugfs_remove(priv->debug.debugfs_recv);
654 debugfs_remove(priv->debug.debugfs_xmit);
655 debugfs_remove(priv->debug.debugfs_tgt_stats);
656 debugfs_remove(priv->debug.debugfs_phy);
657}
658
Sujithe1572c52010-03-24 13:42:13 +0530659int ath9k_htc_debug_create_root(void)
Sujithfb9987d2010-03-17 14:25:25 +0530660{
661 ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
662 if (!ath9k_debugfs_root)
663 return -ENOENT;
664
665 return 0;
666}
667
Sujithe1572c52010-03-24 13:42:13 +0530668void ath9k_htc_debug_remove_root(void)
Sujithfb9987d2010-03-17 14:25:25 +0530669{
670 debugfs_remove(ath9k_debugfs_root);
671 ath9k_debugfs_root = NULL;
672}
673
674#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
675
676/*******/
677/* ANI */
678/*******/
679
680static void ath_start_ani(struct ath9k_htc_priv *priv)
681{
682 struct ath_common *common = ath9k_hw_common(priv->ah);
683 unsigned long timestamp = jiffies_to_msecs(jiffies);
684
685 common->ani.longcal_timer = timestamp;
686 common->ani.shortcal_timer = timestamp;
687 common->ani.checkani_timer = timestamp;
688
689 ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
690 msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
691}
692
693void ath9k_ani_work(struct work_struct *work)
694{
695 struct ath9k_htc_priv *priv =
696 container_of(work, struct ath9k_htc_priv,
697 ath9k_ani_work.work);
698 struct ath_hw *ah = priv->ah;
699 struct ath_common *common = ath9k_hw_common(ah);
700 bool longcal = false;
701 bool shortcal = false;
702 bool aniflag = false;
703 unsigned int timestamp = jiffies_to_msecs(jiffies);
704 u32 cal_interval, short_cal_interval;
705
706 short_cal_interval = ATH_STA_SHORT_CALINTERVAL;
707
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530708 /* Only calibrate if awake */
709 if (ah->power_mode != ATH9K_PM_AWAKE)
710 goto set_timer;
711
Sujithfb9987d2010-03-17 14:25:25 +0530712 /* Long calibration runs independently of short calibration. */
713 if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
714 longcal = true;
715 ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
716 common->ani.longcal_timer = timestamp;
717 }
718
719 /* Short calibration applies only while caldone is false */
720 if (!common->ani.caldone) {
721 if ((timestamp - common->ani.shortcal_timer) >=
722 short_cal_interval) {
723 shortcal = true;
724 ath_print(common, ATH_DBG_ANI,
725 "shortcal @%lu\n", jiffies);
726 common->ani.shortcal_timer = timestamp;
727 common->ani.resetcal_timer = timestamp;
728 }
729 } else {
730 if ((timestamp - common->ani.resetcal_timer) >=
731 ATH_RESTART_CALINTERVAL) {
732 common->ani.caldone = ath9k_hw_reset_calvalid(ah);
733 if (common->ani.caldone)
734 common->ani.resetcal_timer = timestamp;
735 }
736 }
737
738 /* Verify whether we must check ANI */
739 if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
740 aniflag = true;
741 common->ani.checkani_timer = timestamp;
742 }
743
744 /* Skip all processing if there's nothing to do. */
745 if (longcal || shortcal || aniflag) {
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530746
747 ath9k_htc_ps_wakeup(priv);
748
Sujithfb9987d2010-03-17 14:25:25 +0530749 /* Call ANI routine if necessary */
750 if (aniflag)
751 ath9k_hw_ani_monitor(ah, ah->curchan);
752
753 /* Perform calibration if necessary */
754 if (longcal || shortcal) {
755 common->ani.caldone =
756 ath9k_hw_calibrate(ah, ah->curchan,
757 common->rx_chainmask,
758 longcal);
759
760 if (longcal)
761 common->ani.noise_floor =
762 ath9k_hw_getchan_noise(ah, ah->curchan);
763
764 ath_print(common, ATH_DBG_ANI,
765 " calibrate chan %u/%x nf: %d\n",
766 ah->curchan->channel,
767 ah->curchan->channelFlags,
768 common->ani.noise_floor);
769 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530770
771 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530772 }
773
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530774set_timer:
Sujithfb9987d2010-03-17 14:25:25 +0530775 /*
776 * Set timer interval based on previous results.
777 * The interval must be the shortest necessary to satisfy ANI,
778 * short calibration and long calibration.
779 */
780 cal_interval = ATH_LONG_CALINTERVAL;
781 if (priv->ah->config.enable_ani)
782 cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
783 if (!common->ani.caldone)
784 cal_interval = min(cal_interval, (u32)short_cal_interval);
785
786 ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
787 msecs_to_jiffies(cal_interval));
788}
789
790/*******/
791/* LED */
792/*******/
793
794static void ath9k_led_blink_work(struct work_struct *work)
795{
796 struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
797 ath9k_led_blink_work.work);
798
799 if (!(priv->op_flags & OP_LED_ASSOCIATED))
800 return;
801
802 if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
803 (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
804 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
805 else
806 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
807 (priv->op_flags & OP_LED_ON) ? 1 : 0);
808
809 ieee80211_queue_delayed_work(priv->hw,
810 &priv->ath9k_led_blink_work,
811 (priv->op_flags & OP_LED_ON) ?
812 msecs_to_jiffies(priv->led_off_duration) :
813 msecs_to_jiffies(priv->led_on_duration));
814
815 priv->led_on_duration = priv->led_on_cnt ?
816 max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
817 ATH_LED_ON_DURATION_IDLE;
818 priv->led_off_duration = priv->led_off_cnt ?
819 max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
820 ATH_LED_OFF_DURATION_IDLE;
821 priv->led_on_cnt = priv->led_off_cnt = 0;
822
823 if (priv->op_flags & OP_LED_ON)
824 priv->op_flags &= ~OP_LED_ON;
825 else
826 priv->op_flags |= OP_LED_ON;
827}
828
829static void ath9k_led_brightness_work(struct work_struct *work)
830{
831 struct ath_led *led = container_of(work, struct ath_led,
832 brightness_work.work);
833 struct ath9k_htc_priv *priv = led->priv;
834
835 switch (led->brightness) {
836 case LED_OFF:
837 if (led->led_type == ATH_LED_ASSOC ||
838 led->led_type == ATH_LED_RADIO) {
839 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
840 (led->led_type == ATH_LED_RADIO));
841 priv->op_flags &= ~OP_LED_ASSOCIATED;
842 if (led->led_type == ATH_LED_RADIO)
843 priv->op_flags &= ~OP_LED_ON;
844 } else {
845 priv->led_off_cnt++;
846 }
847 break;
848 case LED_FULL:
849 if (led->led_type == ATH_LED_ASSOC) {
850 priv->op_flags |= OP_LED_ASSOCIATED;
851 ieee80211_queue_delayed_work(priv->hw,
852 &priv->ath9k_led_blink_work, 0);
853 } else if (led->led_type == ATH_LED_RADIO) {
854 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
855 priv->op_flags |= OP_LED_ON;
856 } else {
857 priv->led_on_cnt++;
858 }
859 break;
860 default:
861 break;
862 }
863}
864
865static void ath9k_led_brightness(struct led_classdev *led_cdev,
866 enum led_brightness brightness)
867{
868 struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
869 struct ath9k_htc_priv *priv = led->priv;
870
871 led->brightness = brightness;
872 if (!(priv->op_flags & OP_LED_DEINIT))
873 ieee80211_queue_delayed_work(priv->hw,
874 &led->brightness_work, 0);
875}
876
877static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
878{
879 cancel_delayed_work_sync(&priv->radio_led.brightness_work);
880 cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
881 cancel_delayed_work_sync(&priv->tx_led.brightness_work);
882 cancel_delayed_work_sync(&priv->rx_led.brightness_work);
883}
884
885static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
886 char *trigger)
887{
888 int ret;
889
890 led->priv = priv;
891 led->led_cdev.name = led->name;
892 led->led_cdev.default_trigger = trigger;
893 led->led_cdev.brightness_set = ath9k_led_brightness;
894
895 ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
896 if (ret)
897 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
898 "Failed to register led:%s", led->name);
899 else
900 led->registered = 1;
901
902 INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
903
904 return ret;
905}
906
907static void ath9k_unregister_led(struct ath_led *led)
908{
909 if (led->registered) {
910 led_classdev_unregister(&led->led_cdev);
911 led->registered = 0;
912 }
913}
914
915void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
916{
917 priv->op_flags |= OP_LED_DEINIT;
918 ath9k_unregister_led(&priv->assoc_led);
919 priv->op_flags &= ~OP_LED_ASSOCIATED;
920 ath9k_unregister_led(&priv->tx_led);
921 ath9k_unregister_led(&priv->rx_led);
922 ath9k_unregister_led(&priv->radio_led);
Sujithfb9987d2010-03-17 14:25:25 +0530923}
924
925void ath9k_init_leds(struct ath9k_htc_priv *priv)
926{
927 char *trigger;
928 int ret;
929
930 if (AR_SREV_9287(priv->ah))
931 priv->ah->led_pin = ATH_LED_PIN_9287;
932 else if (AR_SREV_9271(priv->ah))
933 priv->ah->led_pin = ATH_LED_PIN_9271;
934 else
935 priv->ah->led_pin = ATH_LED_PIN_DEF;
936
937 /* Configure gpio 1 for output */
938 ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
939 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
940 /* LED off, active low */
941 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
942
943 INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
944
945 trigger = ieee80211_get_radio_led_name(priv->hw);
946 snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
947 "ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
948 ret = ath9k_register_led(priv, &priv->radio_led, trigger);
949 priv->radio_led.led_type = ATH_LED_RADIO;
950 if (ret)
951 goto fail;
952
953 trigger = ieee80211_get_assoc_led_name(priv->hw);
954 snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
955 "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
956 ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
957 priv->assoc_led.led_type = ATH_LED_ASSOC;
958 if (ret)
959 goto fail;
960
961 trigger = ieee80211_get_tx_led_name(priv->hw);
962 snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
963 "ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
964 ret = ath9k_register_led(priv, &priv->tx_led, trigger);
965 priv->tx_led.led_type = ATH_LED_TX;
966 if (ret)
967 goto fail;
968
969 trigger = ieee80211_get_rx_led_name(priv->hw);
970 snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
971 "ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
972 ret = ath9k_register_led(priv, &priv->rx_led, trigger);
973 priv->rx_led.led_type = ATH_LED_RX;
974 if (ret)
975 goto fail;
976
977 priv->op_flags &= ~OP_LED_DEINIT;
978
979 return;
980
981fail:
982 cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
983 ath9k_deinit_leds(priv);
984}
985
986/*******************/
987/* Rfkill */
988/*******************/
989
990static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
991{
992 return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
993 priv->ah->rfkill_polarity;
994}
995
996static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
997{
998 struct ath9k_htc_priv *priv = hw->priv;
999 bool blocked = !!ath_is_rfkill_set(priv);
1000
1001 wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
1002}
1003
1004void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
1005{
1006 if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
1007 wiphy_rfkill_start_polling(priv->hw->wiphy);
1008}
1009
Sujith881ac6a2010-06-01 15:14:11 +05301010static void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
1011{
1012 struct ath9k_htc_priv *priv = hw->priv;
1013 struct ath_hw *ah = priv->ah;
1014 struct ath_common *common = ath9k_hw_common(ah);
1015 int ret;
1016 u8 cmd_rsp;
1017
1018 if (!ah->curchan)
1019 ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
1020
1021 /* Reset the HW */
1022 ret = ath9k_hw_reset(ah, ah->curchan, false);
1023 if (ret) {
1024 ath_print(common, ATH_DBG_FATAL,
1025 "Unable to reset hardware; reset status %d "
1026 "(freq %u MHz)\n", ret, ah->curchan->channel);
1027 }
1028
1029 ath_update_txpow(priv);
1030
1031 /* Start RX */
1032 WMI_CMD(WMI_START_RECV_CMDID);
1033 ath9k_host_rx_init(priv);
1034
1035 /* Start TX */
1036 htc_start(priv->htc);
1037 spin_lock_bh(&priv->tx_lock);
1038 priv->tx_queues_stop = false;
1039 spin_unlock_bh(&priv->tx_lock);
1040 ieee80211_wake_queues(hw);
1041
1042 WMI_CMD(WMI_ENABLE_INTR_CMDID);
1043
1044 /* Enable LED */
1045 ath9k_hw_cfg_output(ah, ah->led_pin,
1046 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
1047 ath9k_hw_set_gpio(ah, ah->led_pin, 0);
1048}
1049
1050static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
1051{
1052 struct ath9k_htc_priv *priv = hw->priv;
1053 struct ath_hw *ah = priv->ah;
1054 struct ath_common *common = ath9k_hw_common(ah);
1055 int ret;
1056 u8 cmd_rsp;
1057
1058 ath9k_htc_ps_wakeup(priv);
1059
1060 /* Disable LED */
1061 ath9k_hw_set_gpio(ah, ah->led_pin, 1);
1062 ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
1063
1064 WMI_CMD(WMI_DISABLE_INTR_CMDID);
1065
1066 /* Stop TX */
1067 ieee80211_stop_queues(hw);
1068 htc_stop(priv->htc);
1069 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
1070 skb_queue_purge(&priv->tx_queue);
1071
1072 /* Stop RX */
1073 WMI_CMD(WMI_STOP_RECV_CMDID);
1074
Sujith21d51302010-06-01 15:14:18 +05301075 /*
1076 * The MIB counters have to be disabled here,
1077 * since the target doesn't do it.
1078 */
1079 ath9k_hw_disable_mib_counters(ah);
1080
Sujith881ac6a2010-06-01 15:14:11 +05301081 if (!ah->curchan)
1082 ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
1083
1084 /* Reset the HW */
1085 ret = ath9k_hw_reset(ah, ah->curchan, false);
1086 if (ret) {
1087 ath_print(common, ATH_DBG_FATAL,
1088 "Unable to reset hardware; reset status %d "
1089 "(freq %u MHz)\n", ret, ah->curchan->channel);
1090 }
1091
1092 /* Disable the PHY */
1093 ath9k_hw_phy_disable(ah);
1094
1095 ath9k_htc_ps_restore(priv);
1096 ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
1097}
1098
Sujithfb9987d2010-03-17 14:25:25 +05301099/**********************/
1100/* mac80211 Callbacks */
1101/**********************/
1102
1103static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1104{
1105 struct ieee80211_hdr *hdr;
1106 struct ath9k_htc_priv *priv = hw->priv;
Sujith7757dfe2010-03-29 16:07:17 +05301107 int padpos, padsize, ret;
Sujithfb9987d2010-03-17 14:25:25 +05301108
1109 hdr = (struct ieee80211_hdr *) skb->data;
1110
1111 /* Add the padding after the header if this is not already done */
1112 padpos = ath9k_cmn_padpos(hdr->frame_control);
1113 padsize = padpos & 3;
1114 if (padsize && skb->len > padpos) {
1115 if (skb_headroom(skb) < padsize)
1116 return -1;
1117 skb_push(skb, padsize);
1118 memmove(skb->data, skb->data + padsize, padpos);
1119 }
1120
Sujith7757dfe2010-03-29 16:07:17 +05301121 ret = ath9k_htc_tx_start(priv, skb);
1122 if (ret != 0) {
1123 if (ret == -ENOMEM) {
1124 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1125 "Stopping TX queues\n");
1126 ieee80211_stop_queues(hw);
1127 spin_lock_bh(&priv->tx_lock);
1128 priv->tx_queues_stop = true;
1129 spin_unlock_bh(&priv->tx_lock);
1130 } else {
1131 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
1132 "Tx failed");
1133 }
Sujithfb9987d2010-03-17 14:25:25 +05301134 goto fail_tx;
1135 }
1136
1137 return 0;
1138
1139fail_tx:
1140 dev_kfree_skb_any(skb);
1141 return 0;
1142}
1143
Sujith881ac6a2010-06-01 15:14:11 +05301144static int ath9k_htc_start(struct ieee80211_hw *hw)
Sujithfb9987d2010-03-17 14:25:25 +05301145{
1146 struct ath9k_htc_priv *priv = hw->priv;
1147 struct ath_hw *ah = priv->ah;
1148 struct ath_common *common = ath9k_hw_common(ah);
1149 struct ieee80211_channel *curchan = hw->conf.channel;
1150 struct ath9k_channel *init_channel;
1151 int ret = 0;
1152 enum htc_phymode mode;
Sujith7f1f5a02010-04-16 11:54:03 +05301153 __be16 htc_mode;
Sujithfb9987d2010-03-17 14:25:25 +05301154 u8 cmd_rsp;
1155
Sujith881ac6a2010-06-01 15:14:11 +05301156 mutex_lock(&priv->mutex);
1157
Sujithfb9987d2010-03-17 14:25:25 +05301158 ath_print(common, ATH_DBG_CONFIG,
1159 "Starting driver with initial channel: %d MHz\n",
1160 curchan->center_freq);
1161
Sujith21d51302010-06-01 15:14:18 +05301162 /* Ensure that HW is awake before flushing RX */
1163 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1164 WMI_CMD(WMI_FLUSH_RECV_CMDID);
1165
Sujithfb9987d2010-03-17 14:25:25 +05301166 /* setup initial channel */
1167 init_channel = ath9k_cmn_get_curchannel(hw, ah);
1168
1169 /* Reset SERDES registers */
1170 ath9k_hw_configpcipowersave(ah, 0, 0);
1171
1172 ath9k_hw_htc_resetinit(ah);
1173 ret = ath9k_hw_reset(ah, init_channel, false);
1174 if (ret) {
1175 ath_print(common, ATH_DBG_FATAL,
1176 "Unable to reset hardware; reset status %d "
1177 "(freq %u MHz)\n", ret, curchan->center_freq);
Sujith881ac6a2010-06-01 15:14:11 +05301178 mutex_unlock(&priv->mutex);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301179 return ret;
Sujithfb9987d2010-03-17 14:25:25 +05301180 }
1181
1182 ath_update_txpow(priv);
1183
1184 mode = ath9k_htc_get_curmode(priv, init_channel);
1185 htc_mode = cpu_to_be16(mode);
1186 WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
Sujithfb9987d2010-03-17 14:25:25 +05301187 WMI_CMD(WMI_ATH_INIT_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301188 WMI_CMD(WMI_START_RECV_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301189
1190 ath9k_host_rx_init(priv);
1191
1192 priv->op_flags &= ~OP_INVALID;
1193 htc_start(priv->htc);
1194
Sujith7757dfe2010-03-29 16:07:17 +05301195 spin_lock_bh(&priv->tx_lock);
1196 priv->tx_queues_stop = false;
1197 spin_unlock_bh(&priv->tx_lock);
1198
1199 ieee80211_wake_queues(hw);
1200
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301201 mutex_unlock(&priv->mutex);
1202
1203 return ret;
1204}
1205
Sujith881ac6a2010-06-01 15:14:11 +05301206static void ath9k_htc_stop(struct ieee80211_hw *hw)
Sujithfb9987d2010-03-17 14:25:25 +05301207{
1208 struct ath9k_htc_priv *priv = hw->priv;
1209 struct ath_hw *ah = priv->ah;
1210 struct ath_common *common = ath9k_hw_common(ah);
1211 int ret = 0;
1212 u8 cmd_rsp;
1213
Sujith881ac6a2010-06-01 15:14:11 +05301214 mutex_lock(&priv->mutex);
1215
Sujithfb9987d2010-03-17 14:25:25 +05301216 if (priv->op_flags & OP_INVALID) {
1217 ath_print(common, ATH_DBG_ANY, "Device not present\n");
Sujith881ac6a2010-06-01 15:14:11 +05301218 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301219 return;
1220 }
1221
Sujith7073daa2010-04-23 10:28:13 +05301222 /* Cancel all the running timers/work .. */
1223 cancel_work_sync(&priv->ps_work);
1224 cancel_delayed_work_sync(&priv->ath9k_ani_work);
Sujith7073daa2010-04-23 10:28:13 +05301225 cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
1226 ath9k_led_stop_brightness(priv);
1227
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301228 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301229 htc_stop(priv->htc);
1230 WMI_CMD(WMI_DISABLE_INTR_CMDID);
1231 WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
1232 WMI_CMD(WMI_STOP_RECV_CMDID);
Sujithfb9987d2010-03-17 14:25:25 +05301233 skb_queue_purge(&priv->tx_queue);
1234
1235 /* Remove monitor interface here */
1236 if (ah->opmode == NL80211_IFTYPE_MONITOR) {
1237 if (ath9k_htc_remove_monitor_interface(priv))
1238 ath_print(common, ATH_DBG_FATAL,
1239 "Unable to remove monitor interface\n");
1240 else
1241 ath_print(common, ATH_DBG_CONFIG,
1242 "Monitor interface removed\n");
1243 }
1244
Sujithe9201f02010-06-01 15:14:17 +05301245 ath9k_hw_phy_disable(ah);
1246 ath9k_hw_disable(ah);
1247 ath9k_hw_configpcipowersave(ah, 1, 1);
1248 ath9k_htc_ps_restore(priv);
1249 ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
1250
Sujithfb9987d2010-03-17 14:25:25 +05301251 priv->op_flags |= OP_INVALID;
Sujithfb9987d2010-03-17 14:25:25 +05301252
1253 ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301254 mutex_unlock(&priv->mutex);
1255}
1256
Sujithfb9987d2010-03-17 14:25:25 +05301257static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
1258 struct ieee80211_vif *vif)
1259{
1260 struct ath9k_htc_priv *priv = hw->priv;
1261 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1262 struct ath_common *common = ath9k_hw_common(priv->ah);
1263 struct ath9k_htc_target_vif hvif;
1264 int ret = 0;
1265 u8 cmd_rsp;
1266
1267 mutex_lock(&priv->mutex);
1268
1269 /* Only one interface for now */
1270 if (priv->nvifs > 0) {
1271 ret = -ENOBUFS;
1272 goto out;
1273 }
1274
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301275 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301276 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1277 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1278
1279 switch (vif->type) {
1280 case NL80211_IFTYPE_STATION:
1281 hvif.opmode = cpu_to_be32(HTC_M_STA);
1282 break;
1283 case NL80211_IFTYPE_ADHOC:
1284 hvif.opmode = cpu_to_be32(HTC_M_IBSS);
1285 break;
1286 default:
1287 ath_print(common, ATH_DBG_FATAL,
1288 "Interface type %d not yet supported\n", vif->type);
1289 ret = -EOPNOTSUPP;
1290 goto out;
1291 }
1292
1293 ath_print(common, ATH_DBG_CONFIG,
1294 "Attach a VIF of type: %d\n", vif->type);
1295
1296 priv->ah->opmode = vif->type;
1297
1298 /* Index starts from zero on the target */
1299 avp->index = hvif.index = priv->nvifs;
1300 hvif.rtsthreshold = cpu_to_be16(2304);
1301 WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
1302 if (ret)
1303 goto out;
1304
1305 priv->nvifs++;
1306
1307 /*
1308 * We need a node in target to tx mgmt frames
1309 * before association.
1310 */
1311 ret = ath9k_htc_add_station(priv, vif, NULL);
1312 if (ret)
1313 goto out;
1314
1315 ret = ath9k_htc_update_cap_target(priv);
1316 if (ret)
1317 ath_print(common, ATH_DBG_CONFIG, "Failed to update"
1318 " capability in target \n");
1319
1320 priv->vif = vif;
1321out:
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301322 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301323 mutex_unlock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301324
Sujithfb9987d2010-03-17 14:25:25 +05301325 return ret;
1326}
1327
1328static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
1329 struct ieee80211_vif *vif)
1330{
1331 struct ath9k_htc_priv *priv = hw->priv;
1332 struct ath_common *common = ath9k_hw_common(priv->ah);
1333 struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1334 struct ath9k_htc_target_vif hvif;
1335 int ret = 0;
1336 u8 cmd_rsp;
1337
1338 ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
1339
1340 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301341 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301342
1343 memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1344 memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1345 hvif.index = avp->index;
1346 WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
1347 priv->nvifs--;
1348
1349 ath9k_htc_remove_station(priv, vif, NULL);
Sujithfb9987d2010-03-17 14:25:25 +05301350 priv->vif = NULL;
1351
Sujithcb551df2010-06-01 15:14:12 +05301352 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301353 mutex_unlock(&priv->mutex);
1354}
1355
1356static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
1357{
1358 struct ath9k_htc_priv *priv = hw->priv;
1359 struct ath_common *common = ath9k_hw_common(priv->ah);
1360 struct ieee80211_conf *conf = &hw->conf;
1361
1362 mutex_lock(&priv->mutex);
1363
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301364 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1365 bool enable_radio = false;
1366 bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
1367
Sujith23367762010-06-01 15:14:16 +05301368 mutex_lock(&priv->htc_pm_lock);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301369 if (!idle && priv->ps_idle)
1370 enable_radio = true;
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301371 priv->ps_idle = idle;
Sujith23367762010-06-01 15:14:16 +05301372 mutex_unlock(&priv->htc_pm_lock);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301373
1374 if (enable_radio) {
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301375 ath_print(common, ATH_DBG_CONFIG,
1376 "not-idle: enabling radio\n");
Sujith23367762010-06-01 15:14:16 +05301377 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1378 ath9k_htc_radio_enable(hw);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301379 }
1380 }
1381
Sujithfb9987d2010-03-17 14:25:25 +05301382 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1383 struct ieee80211_channel *curchan = hw->conf.channel;
1384 int pos = curchan->hw_value;
Sujithfb9987d2010-03-17 14:25:25 +05301385
1386 ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
1387 curchan->center_freq);
1388
Sujithfb9987d2010-03-17 14:25:25 +05301389 ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
1390
1391 if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
1392 ath_print(common, ATH_DBG_FATAL,
1393 "Unable to set channel\n");
1394 mutex_unlock(&priv->mutex);
1395 return -EINVAL;
1396 }
1397
1398 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301399 if (changed & IEEE80211_CONF_CHANGE_PS) {
1400 if (conf->flags & IEEE80211_CONF_PS) {
1401 ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
1402 priv->ps_enabled = true;
1403 } else {
1404 priv->ps_enabled = false;
1405 cancel_work_sync(&priv->ps_work);
1406 ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1407 }
1408 }
Sujithfb9987d2010-03-17 14:25:25 +05301409
1410 if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
1411 if (conf->flags & IEEE80211_CONF_MONITOR) {
1412 if (ath9k_htc_add_monitor_interface(priv))
1413 ath_print(common, ATH_DBG_FATAL,
1414 "Failed to set monitor mode\n");
1415 else
1416 ath_print(common, ATH_DBG_CONFIG,
1417 "HW opmode set to Monitor mode\n");
1418 }
1419 }
1420
Sujith23367762010-06-01 15:14:16 +05301421 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
1422 mutex_lock(&priv->htc_pm_lock);
1423 if (!priv->ps_idle) {
1424 mutex_unlock(&priv->htc_pm_lock);
1425 goto out;
1426 }
1427 mutex_unlock(&priv->htc_pm_lock);
1428
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301429 ath_print(common, ATH_DBG_CONFIG,
1430 "idle: disabling radio\n");
Sujith881ac6a2010-06-01 15:14:11 +05301431 ath9k_htc_radio_disable(hw);
Vivek Natarajan8a8572a2010-04-27 13:05:37 +05301432 }
1433
Sujith23367762010-06-01 15:14:16 +05301434out:
Sujithfb9987d2010-03-17 14:25:25 +05301435 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301436 return 0;
1437}
1438
1439#define SUPPORTED_FILTERS \
1440 (FIF_PROMISC_IN_BSS | \
1441 FIF_ALLMULTI | \
1442 FIF_CONTROL | \
1443 FIF_PSPOLL | \
1444 FIF_OTHER_BSS | \
1445 FIF_BCN_PRBRESP_PROMISC | \
1446 FIF_FCSFAIL)
1447
1448static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
1449 unsigned int changed_flags,
1450 unsigned int *total_flags,
1451 u64 multicast)
1452{
1453 struct ath9k_htc_priv *priv = hw->priv;
1454 u32 rfilt;
1455
1456 mutex_lock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301457 ath9k_htc_ps_wakeup(priv);
Sujithcb551df2010-06-01 15:14:12 +05301458
Sujithfb9987d2010-03-17 14:25:25 +05301459 changed_flags &= SUPPORTED_FILTERS;
1460 *total_flags &= SUPPORTED_FILTERS;
1461
1462 priv->rxfilter = *total_flags;
Sujith0995d112010-03-29 16:07:09 +05301463 rfilt = ath9k_htc_calcrxfilter(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301464 ath9k_hw_setrxfilter(priv->ah, rfilt);
1465
1466 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
1467 "Set HW RX filter: 0x%x\n", rfilt);
1468
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301469 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301470 mutex_unlock(&priv->mutex);
1471}
1472
Sujithabd984e2010-05-18 15:26:04 +05301473static int ath9k_htc_sta_add(struct ieee80211_hw *hw,
1474 struct ieee80211_vif *vif,
1475 struct ieee80211_sta *sta)
Sujithfb9987d2010-03-17 14:25:25 +05301476{
1477 struct ath9k_htc_priv *priv = hw->priv;
1478 int ret;
1479
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301480 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301481 ath9k_htc_ps_wakeup(priv);
Sujithabd984e2010-05-18 15:26:04 +05301482 ret = ath9k_htc_add_station(priv, vif, sta);
1483 if (!ret)
1484 ath9k_htc_init_rate(priv, sta);
Sujithcb551df2010-06-01 15:14:12 +05301485 ath9k_htc_ps_restore(priv);
Sujith.Manoharan@atheros.com05a30f92010-05-11 16:24:38 +05301486 mutex_unlock(&priv->mutex);
Sujithabd984e2010-05-18 15:26:04 +05301487
1488 return ret;
1489}
1490
1491static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
1492 struct ieee80211_vif *vif,
1493 struct ieee80211_sta *sta)
1494{
1495 struct ath9k_htc_priv *priv = hw->priv;
1496 int ret;
1497
1498 mutex_lock(&priv->mutex);
1499 ath9k_htc_ps_wakeup(priv);
1500 ret = ath9k_htc_remove_station(priv, vif, sta);
1501 ath9k_htc_ps_restore(priv);
1502 mutex_unlock(&priv->mutex);
1503
1504 return ret;
Sujithfb9987d2010-03-17 14:25:25 +05301505}
1506
1507static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
1508 const struct ieee80211_tx_queue_params *params)
1509{
1510 struct ath9k_htc_priv *priv = hw->priv;
1511 struct ath_common *common = ath9k_hw_common(priv->ah);
1512 struct ath9k_tx_queue_info qi;
1513 int ret = 0, qnum;
1514
1515 if (queue >= WME_NUM_AC)
1516 return 0;
1517
1518 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301519 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301520
1521 memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
1522
1523 qi.tqi_aifs = params->aifs;
1524 qi.tqi_cwmin = params->cw_min;
1525 qi.tqi_cwmax = params->cw_max;
1526 qi.tqi_burstTime = params->txop;
1527
1528 qnum = get_hw_qnum(queue, priv->hwq_map);
1529
1530 ath_print(common, ATH_DBG_CONFIG,
1531 "Configure tx [queue/hwq] [%d/%d], "
1532 "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
1533 queue, qnum, params->aifs, params->cw_min,
1534 params->cw_max, params->txop);
1535
Sujithe1572c52010-03-24 13:42:13 +05301536 ret = ath_htc_txq_update(priv, qnum, &qi);
Sujith764580f2010-06-01 15:14:19 +05301537 if (ret) {
Sujithfb9987d2010-03-17 14:25:25 +05301538 ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
Sujith764580f2010-06-01 15:14:19 +05301539 goto out;
1540 }
Sujithfb9987d2010-03-17 14:25:25 +05301541
Sujith764580f2010-06-01 15:14:19 +05301542 if ((priv->ah->opmode == NL80211_IFTYPE_ADHOC) &&
Felix Fietkaue8c35a72010-06-12 00:33:50 -04001543 (qnum == priv->hwq_map[WME_AC_BE]))
Sujith764580f2010-06-01 15:14:19 +05301544 ath9k_htc_beaconq_config(priv);
1545out:
Sujithcb551df2010-06-01 15:14:12 +05301546 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301547 mutex_unlock(&priv->mutex);
1548
1549 return ret;
1550}
1551
1552static int ath9k_htc_set_key(struct ieee80211_hw *hw,
1553 enum set_key_cmd cmd,
1554 struct ieee80211_vif *vif,
1555 struct ieee80211_sta *sta,
1556 struct ieee80211_key_conf *key)
1557{
1558 struct ath9k_htc_priv *priv = hw->priv;
1559 struct ath_common *common = ath9k_hw_common(priv->ah);
1560 int ret = 0;
1561
Sujithe1572c52010-03-24 13:42:13 +05301562 if (htc_modparam_nohwcrypt)
Sujithfb9987d2010-03-17 14:25:25 +05301563 return -ENOSPC;
1564
1565 mutex_lock(&priv->mutex);
1566 ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301567 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301568
1569 switch (cmd) {
1570 case SET_KEY:
1571 ret = ath9k_cmn_key_config(common, vif, sta, key);
1572 if (ret >= 0) {
1573 key->hw_key_idx = ret;
1574 /* push IV and Michael MIC generation to stack */
1575 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
1576 if (key->alg == ALG_TKIP)
1577 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
1578 if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
1579 key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
1580 ret = 0;
1581 }
1582 break;
1583 case DISABLE_KEY:
1584 ath9k_cmn_key_delete(common, key);
1585 break;
1586 default:
1587 ret = -EINVAL;
1588 }
1589
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301590 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301591 mutex_unlock(&priv->mutex);
1592
1593 return ret;
1594}
1595
1596static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
1597 struct ieee80211_vif *vif,
1598 struct ieee80211_bss_conf *bss_conf,
1599 u32 changed)
1600{
1601 struct ath9k_htc_priv *priv = hw->priv;
1602 struct ath_hw *ah = priv->ah;
1603 struct ath_common *common = ath9k_hw_common(ah);
1604
1605 mutex_lock(&priv->mutex);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301606 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301607
1608 if (changed & BSS_CHANGED_ASSOC) {
1609 common->curaid = bss_conf->assoc ?
1610 bss_conf->aid : 0;
1611 ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
1612 bss_conf->assoc);
1613
1614 if (bss_conf->assoc) {
1615 priv->op_flags |= OP_ASSOCIATED;
1616 ath_start_ani(priv);
1617 } else {
1618 priv->op_flags &= ~OP_ASSOCIATED;
1619 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1620 }
1621 }
1622
1623 if (changed & BSS_CHANGED_BSSID) {
1624 /* Set BSSID */
1625 memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1626 ath9k_hw_write_associd(ah);
1627
1628 ath_print(common, ATH_DBG_CONFIG,
1629 "BSSID: %pM aid: 0x%x\n",
1630 common->curbssid, common->curaid);
1631 }
1632
1633 if ((changed & BSS_CHANGED_BEACON_INT) ||
1634 (changed & BSS_CHANGED_BEACON) ||
1635 ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1636 bss_conf->enable_beacon)) {
1637 priv->op_flags |= OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301638 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301639 }
1640
Sujithfb9987d2010-03-17 14:25:25 +05301641 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1642 !bss_conf->enable_beacon) {
1643 priv->op_flags &= ~OP_ENABLE_BEACON;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301644 ath9k_htc_beacon_config(priv, vif);
Sujithfb9987d2010-03-17 14:25:25 +05301645 }
1646
1647 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1648 ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
1649 bss_conf->use_short_preamble);
1650 if (bss_conf->use_short_preamble)
1651 priv->op_flags |= OP_PREAMBLE_SHORT;
1652 else
1653 priv->op_flags &= ~OP_PREAMBLE_SHORT;
1654 }
1655
1656 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1657 ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
1658 bss_conf->use_cts_prot);
1659 if (bss_conf->use_cts_prot &&
1660 hw->conf.channel->band != IEEE80211_BAND_5GHZ)
1661 priv->op_flags |= OP_PROTECT_ENABLE;
1662 else
1663 priv->op_flags &= ~OP_PROTECT_ENABLE;
1664 }
1665
1666 if (changed & BSS_CHANGED_ERP_SLOT) {
1667 if (bss_conf->use_short_slot)
1668 ah->slottime = 9;
1669 else
1670 ah->slottime = 20;
1671
1672 ath9k_hw_init_global_settings(ah);
1673 }
1674
Sujith2c76ef82010-05-17 12:01:18 +05301675 if (changed & BSS_CHANGED_HT)
1676 ath9k_htc_update_rate(priv, vif, bss_conf);
1677
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301678 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301679 mutex_unlock(&priv->mutex);
1680}
1681
1682static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
1683{
1684 struct ath9k_htc_priv *priv = hw->priv;
1685 u64 tsf;
1686
1687 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301688 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301689 tsf = ath9k_hw_gettsf64(priv->ah);
Sujithcb551df2010-06-01 15:14:12 +05301690 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301691 mutex_unlock(&priv->mutex);
1692
1693 return tsf;
1694}
1695
1696static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
1697{
1698 struct ath9k_htc_priv *priv = hw->priv;
1699
1700 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301701 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301702 ath9k_hw_settsf64(priv->ah, tsf);
Sujithcb551df2010-06-01 15:14:12 +05301703 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301704 mutex_unlock(&priv->mutex);
1705}
1706
1707static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
1708{
1709 struct ath9k_htc_priv *priv = hw->priv;
1710
1711 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301712 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301713 ath9k_hw_reset_tsf(priv->ah);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301714 ath9k_htc_ps_restore(priv);
Sujithcb551df2010-06-01 15:14:12 +05301715 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301716}
1717
1718static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
1719 struct ieee80211_vif *vif,
1720 enum ieee80211_ampdu_mlme_action action,
1721 struct ieee80211_sta *sta,
1722 u16 tid, u16 *ssn)
1723{
1724 struct ath9k_htc_priv *priv = hw->priv;
Sujithfb9987d2010-03-17 14:25:25 +05301725 struct ath9k_htc_sta *ista;
Sujithd7ca2132010-06-15 10:24:37 +05301726 int ret = 0;
Sujithfb9987d2010-03-17 14:25:25 +05301727
1728 switch (action) {
1729 case IEEE80211_AMPDU_RX_START:
1730 break;
1731 case IEEE80211_AMPDU_RX_STOP:
1732 break;
1733 case IEEE80211_AMPDU_TX_START:
Sujithd7ca2132010-06-15 10:24:37 +05301734 ret = ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
1735 if (!ret)
1736 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1737 break;
Sujithfb9987d2010-03-17 14:25:25 +05301738 case IEEE80211_AMPDU_TX_STOP:
Sujithd7ca2132010-06-15 10:24:37 +05301739 ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid);
1740 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
Sujithfb9987d2010-03-17 14:25:25 +05301741 break;
1742 case IEEE80211_AMPDU_TX_OPERATIONAL:
1743 ista = (struct ath9k_htc_sta *) sta->drv_priv;
Sujithd7ca2132010-06-15 10:24:37 +05301744 spin_lock_bh(&priv->tx_lock);
Sujithfb9987d2010-03-17 14:25:25 +05301745 ista->tid_state[tid] = AGGR_OPERATIONAL;
Sujithd7ca2132010-06-15 10:24:37 +05301746 spin_unlock_bh(&priv->tx_lock);
Sujithfb9987d2010-03-17 14:25:25 +05301747 break;
1748 default:
1749 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
1750 "Unknown AMPDU action\n");
1751 }
1752
Sujithd7ca2132010-06-15 10:24:37 +05301753 return ret;
Sujithfb9987d2010-03-17 14:25:25 +05301754}
1755
1756static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
1757{
1758 struct ath9k_htc_priv *priv = hw->priv;
1759
1760 mutex_lock(&priv->mutex);
1761 spin_lock_bh(&priv->beacon_lock);
1762 priv->op_flags |= OP_SCANNING;
1763 spin_unlock_bh(&priv->beacon_lock);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301764 cancel_work_sync(&priv->ps_work);
Sujithfb9987d2010-03-17 14:25:25 +05301765 cancel_delayed_work_sync(&priv->ath9k_ani_work);
1766 mutex_unlock(&priv->mutex);
1767}
1768
1769static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
1770{
1771 struct ath9k_htc_priv *priv = hw->priv;
1772
1773 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301774 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301775 spin_lock_bh(&priv->beacon_lock);
1776 priv->op_flags &= ~OP_SCANNING;
1777 spin_unlock_bh(&priv->beacon_lock);
1778 priv->op_flags |= OP_FULL_RESET;
Vivek Natarajan1c3652a2010-04-05 14:48:06 +05301779 if (priv->op_flags & OP_ASSOCIATED)
Sujithfcb93922010-04-16 11:53:48 +05301780 ath9k_htc_beacon_config(priv, priv->vif);
Sujithfb9987d2010-03-17 14:25:25 +05301781 ath_start_ani(priv);
Vivek Natarajanbde748a2010-04-05 14:48:05 +05301782 ath9k_htc_ps_restore(priv);
Sujithcb551df2010-06-01 15:14:12 +05301783 mutex_unlock(&priv->mutex);
Sujithfb9987d2010-03-17 14:25:25 +05301784}
1785
1786static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1787{
1788 return 0;
1789}
1790
1791static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
1792 u8 coverage_class)
1793{
1794 struct ath9k_htc_priv *priv = hw->priv;
1795
1796 mutex_lock(&priv->mutex);
Sujithcb551df2010-06-01 15:14:12 +05301797 ath9k_htc_ps_wakeup(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301798 priv->ah->coverage_class = coverage_class;
1799 ath9k_hw_init_global_settings(priv->ah);
Sujithcb551df2010-06-01 15:14:12 +05301800 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +05301801 mutex_unlock(&priv->mutex);
1802}
1803
1804struct ieee80211_ops ath9k_htc_ops = {
1805 .tx = ath9k_htc_tx,
1806 .start = ath9k_htc_start,
1807 .stop = ath9k_htc_stop,
1808 .add_interface = ath9k_htc_add_interface,
1809 .remove_interface = ath9k_htc_remove_interface,
1810 .config = ath9k_htc_config,
1811 .configure_filter = ath9k_htc_configure_filter,
Sujithabd984e2010-05-18 15:26:04 +05301812 .sta_add = ath9k_htc_sta_add,
1813 .sta_remove = ath9k_htc_sta_remove,
Sujithfb9987d2010-03-17 14:25:25 +05301814 .conf_tx = ath9k_htc_conf_tx,
1815 .bss_info_changed = ath9k_htc_bss_info_changed,
1816 .set_key = ath9k_htc_set_key,
1817 .get_tsf = ath9k_htc_get_tsf,
1818 .set_tsf = ath9k_htc_set_tsf,
1819 .reset_tsf = ath9k_htc_reset_tsf,
1820 .ampdu_action = ath9k_htc_ampdu_action,
1821 .sw_scan_start = ath9k_htc_sw_scan_start,
1822 .sw_scan_complete = ath9k_htc_sw_scan_complete,
1823 .set_rts_threshold = ath9k_htc_set_rts_threshold,
1824 .rfkill_poll = ath9k_htc_rfkill_poll_state,
1825 .set_coverage_class = ath9k_htc_set_coverage_class,
1826};