blob: 32438771ca2b0218f27033443d48578140236222 [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
Luis R. Rodriguez9edd9522010-07-13 21:27:25 -0400441static int 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,
445 u16 tid)
Sujithfb9987d2010-03-17 14:25:25 +0530446{
447 struct ath_common *common = ath9k_hw_common(priv->ah);
448 struct ath9k_htc_target_aggr aggr;
Dan Carpenter277a64d2010-05-08 18:23:20 +0200449 struct ath9k_htc_sta *ista;
Sujithfb9987d2010-03-17 14:25:25 +0530450 int ret = 0;
451 u8 cmd_rsp;
452
Dan Carpenter0730d112010-05-08 18:24:02 +0200453 if (tid >= ATH9K_HTC_MAX_TID)
Sujithfb9987d2010-03-17 14:25:25 +0530454 return -EINVAL;
455
Sujithfb9987d2010-03-17 14:25:25 +0530456 memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
Sujithef98c3c2010-03-29 16:07:11 +0530457 ista = (struct ath9k_htc_sta *) sta->drv_priv;
Sujithfb9987d2010-03-17 14:25:25 +0530458
Sujithef98c3c2010-03-29 16:07:11 +0530459 aggr.sta_index = ista->index;
Sujithd7ca2132010-06-15 10:24:37 +0530460 aggr.tidno = tid & 0xf;
461 aggr.aggr_enable = (action == IEEE80211_AMPDU_TX_START) ? true : false;
Sujithef98c3c2010-03-29 16:07:11 +0530462
Sujithfb9987d2010-03-17 14:25:25 +0530463 WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
464 if (ret)
465 ath_print(common, ATH_DBG_CONFIG,
466 "Unable to %s TX aggregation for (%pM, %d)\n",
Sujithd7ca2132010-06-15 10:24:37 +0530467 (aggr.aggr_enable) ? "start" : "stop", sta->addr, tid);
Sujithfb9987d2010-03-17 14:25:25 +0530468 else
469 ath_print(common, ATH_DBG_CONFIG,
Sujithd7ca2132010-06-15 10:24:37 +0530470 "%s TX aggregation for (%pM, %d)\n",
471 (aggr.aggr_enable) ? "Starting" : "Stopping",
472 sta->addr, tid);
473
474 spin_lock_bh(&priv->tx_lock);
475 ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
476 spin_unlock_bh(&priv->tx_lock);
Sujithfb9987d2010-03-17 14:25:25 +0530477
478 return ret;
479}
480
Sujithfb9987d2010-03-17 14:25:25 +0530481/*********/
482/* DEBUG */
483/*********/
484
485#ifdef CONFIG_ATH9K_HTC_DEBUGFS
486
487static int ath9k_debugfs_open(struct inode *inode, struct file *file)
488{
489 file->private_data = inode->i_private;
490 return 0;
491}
492
493static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
494 size_t count, loff_t *ppos)
495{
Joe Perches57674302010-07-12 13:50:06 -0700496 struct ath9k_htc_priv *priv = file->private_data;
Sujithfb9987d2010-03-17 14:25:25 +0530497 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{
Joe Perches57674302010-07-12 13:50:06 -0700539 struct ath9k_htc_priv *priv = file->private_data;
Sujithfb9987d2010-03-17 14:25:25 +0530540 char buf[512];
541 unsigned int len = 0;
542
543 len += snprintf(buf + len, sizeof(buf) - len,
544 "%20s : %10u\n", "Buffers queued",
545 priv->debug.tx_stats.buf_queued);
546 len += snprintf(buf + len, sizeof(buf) - len,
547 "%20s : %10u\n", "Buffers completed",
548 priv->debug.tx_stats.buf_completed);
549 len += snprintf(buf + len, sizeof(buf) - len,
550 "%20s : %10u\n", "SKBs queued",
551 priv->debug.tx_stats.skb_queued);
552 len += snprintf(buf + len, sizeof(buf) - len,
553 "%20s : %10u\n", "SKBs completed",
554 priv->debug.tx_stats.skb_completed);
Sujitheac8e382010-04-16 11:54:00 +0530555 len += snprintf(buf + len, sizeof(buf) - len,
556 "%20s : %10u\n", "SKBs dropped",
557 priv->debug.tx_stats.skb_dropped);
Sujithfb9987d2010-03-17 14:25:25 +0530558
Sujith2edb4582010-05-14 11:18:54 +0530559 len += snprintf(buf + len, sizeof(buf) - len,
560 "%20s : %10u\n", "BE queued",
561 priv->debug.tx_stats.queue_stats[WME_AC_BE]);
562 len += snprintf(buf + len, sizeof(buf) - len,
563 "%20s : %10u\n", "BK queued",
564 priv->debug.tx_stats.queue_stats[WME_AC_BK]);
565 len += snprintf(buf + len, sizeof(buf) - len,
566 "%20s : %10u\n", "VI queued",
567 priv->debug.tx_stats.queue_stats[WME_AC_VI]);
568 len += snprintf(buf + len, sizeof(buf) - len,
569 "%20s : %10u\n", "VO queued",
570 priv->debug.tx_stats.queue_stats[WME_AC_VO]);
571
Sujithfb9987d2010-03-17 14:25:25 +0530572 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
573}
574
575static const struct file_operations fops_xmit = {
576 .read = read_file_xmit,
577 .open = ath9k_debugfs_open,
578 .owner = THIS_MODULE
579};
580
581static ssize_t read_file_recv(struct file *file, char __user *user_buf,
582 size_t count, loff_t *ppos)
583{
Joe Perches57674302010-07-12 13:50:06 -0700584 struct ath9k_htc_priv *priv = file->private_data;
Sujithfb9987d2010-03-17 14:25:25 +0530585 char buf[512];
586 unsigned int len = 0;
587
588 len += snprintf(buf + len, sizeof(buf) - len,
589 "%20s : %10u\n", "SKBs allocated",
590 priv->debug.rx_stats.skb_allocated);
591 len += snprintf(buf + len, sizeof(buf) - len,
592 "%20s : %10u\n", "SKBs completed",
593 priv->debug.rx_stats.skb_completed);
594 len += snprintf(buf + len, sizeof(buf) - len,
595 "%20s : %10u\n", "SKBs Dropped",
596 priv->debug.rx_stats.skb_dropped);
597
598 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
599}
600
601static const struct file_operations fops_recv = {
602 .read = read_file_recv,
603 .open = ath9k_debugfs_open,
604 .owner = THIS_MODULE
605};
606
Sujithe1572c52010-03-24 13:42:13 +0530607int ath9k_htc_init_debug(struct ath_hw *ah)
Sujithfb9987d2010-03-17 14:25:25 +0530608{
609 struct ath_common *common = ath9k_hw_common(ah);
610 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
611
612 if (!ath9k_debugfs_root)
613 return -ENOENT;
614
615 priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy),
616 ath9k_debugfs_root);
617 if (!priv->debug.debugfs_phy)
618 goto err;
619
620 priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR,
621 priv->debug.debugfs_phy,
622 priv, &fops_tgt_stats);
623 if (!priv->debug.debugfs_tgt_stats)
624 goto err;
625
626
627 priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR,
628 priv->debug.debugfs_phy,
629 priv, &fops_xmit);
630 if (!priv->debug.debugfs_xmit)
631 goto err;
632
633 priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR,
634 priv->debug.debugfs_phy,
635 priv, &fops_recv);
636 if (!priv->debug.debugfs_recv)
637 goto err;
638
639 return 0;
640
641err:
Sujithe1572c52010-03-24 13:42:13 +0530642 ath9k_htc_exit_debug(ah);
Sujithfb9987d2010-03-17 14:25:25 +0530643 return -ENOMEM;
644}
645
Sujithe1572c52010-03-24 13:42:13 +0530646void ath9k_htc_exit_debug(struct ath_hw *ah)
Sujithfb9987d2010-03-17 14:25:25 +0530647{
648 struct ath_common *common = ath9k_hw_common(ah);
649 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
650
651 debugfs_remove(priv->debug.debugfs_recv);
652 debugfs_remove(priv->debug.debugfs_xmit);
653 debugfs_remove(priv->debug.debugfs_tgt_stats);
654 debugfs_remove(priv->debug.debugfs_phy);
655}
656
Sujithe1572c52010-03-24 13:42:13 +0530657int ath9k_htc_debug_create_root(void)
Sujithfb9987d2010-03-17 14:25:25 +0530658{
659 ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
660 if (!ath9k_debugfs_root)
661 return -ENOENT;
662
663 return 0;
664}
665
Sujithe1572c52010-03-24 13:42:13 +0530666void ath9k_htc_debug_remove_root(void)
Sujithfb9987d2010-03-17 14:25:25 +0530667{
668 debugfs_remove(ath9k_debugfs_root);
669 ath9k_debugfs_root = NULL;
670}
671
672#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
673
674/*******/
675/* ANI */
676/*******/
677
678static void ath_start_ani(struct ath9k_htc_priv *priv)
679{
680 struct ath_common *common = ath9k_hw_common(priv->ah);
681 unsigned long timestamp = jiffies_to_msecs(jiffies);
682
683 common->ani.longcal_timer = timestamp;
684 common->ani.shortcal_timer = timestamp;
685 common->ani.checkani_timer = timestamp;
686
687 ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
688 msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
689}
690
691void ath9k_ani_work(struct work_struct *work)
692{
693 struct ath9k_htc_priv *priv =
694 container_of(work, struct ath9k_htc_priv,
695 ath9k_ani_work.work);
696 struct ath_hw *ah = priv->ah;
697 struct ath_common *common = ath9k_hw_common(ah);
698 bool longcal = false;
699 bool shortcal = false;
700 bool aniflag = false;
701 unsigned int timestamp = jiffies_to_msecs(jiffies);
702 u32 cal_interval, short_cal_interval;
703
704 short_cal_interval = ATH_STA_SHORT_CALINTERVAL;
705
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530706 /* Only calibrate if awake */
707 if (ah->power_mode != ATH9K_PM_AWAKE)
708 goto set_timer;
709
Sujithfb9987d2010-03-17 14:25:25 +0530710 /* Long calibration runs independently of short calibration. */
711 if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
712 longcal = true;
713 ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
714 common->ani.longcal_timer = timestamp;
715 }
716
717 /* Short calibration applies only while caldone is false */
718 if (!common->ani.caldone) {
719 if ((timestamp - common->ani.shortcal_timer) >=
720 short_cal_interval) {
721 shortcal = true;
722 ath_print(common, ATH_DBG_ANI,
723 "shortcal @%lu\n", jiffies);
724 common->ani.shortcal_timer = timestamp;
725 common->ani.resetcal_timer = timestamp;
726 }
727 } else {
728 if ((timestamp - common->ani.resetcal_timer) >=
729 ATH_RESTART_CALINTERVAL) {
730 common->ani.caldone = ath9k_hw_reset_calvalid(ah);
731 if (common->ani.caldone)
732 common->ani.resetcal_timer = timestamp;
733 }
734 }
735
736 /* Verify whether we must check ANI */
737 if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
738 aniflag = true;
739 common->ani.checkani_timer = timestamp;
740 }
741
742 /* Skip all processing if there's nothing to do. */
743 if (longcal || shortcal || aniflag) {
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530744
745 ath9k_htc_ps_wakeup(priv);
746
Sujithfb9987d2010-03-17 14:25:25 +0530747 /* Call ANI routine if necessary */
748 if (aniflag)
749 ath9k_hw_ani_monitor(ah, ah->curchan);
750
751 /* Perform calibration if necessary */
752 if (longcal || shortcal) {
753 common->ani.caldone =
754 ath9k_hw_calibrate(ah, ah->curchan,
755 common->rx_chainmask,
756 longcal);
757
758 if (longcal)
759 common->ani.noise_floor =
760 ath9k_hw_getchan_noise(ah, ah->curchan);
761
762 ath_print(common, ATH_DBG_ANI,
763 " calibrate chan %u/%x nf: %d\n",
764 ah->curchan->channel,
765 ah->curchan->channelFlags,
766 common->ani.noise_floor);
767 }
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530768
769 ath9k_htc_ps_restore(priv);
Sujithfb9987d2010-03-17 14:25:25 +0530770 }
771
Vivek Natarajanbde748a2010-04-05 14:48:05 +0530772set_timer:
Sujithfb9987d2010-03-17 14:25:25 +0530773 /*
774 * Set timer interval based on previous results.
775 * The interval must be the shortest necessary to satisfy ANI,
776 * short calibration and long calibration.
777 */
778 cal_interval = ATH_LONG_CALINTERVAL;
779 if (priv->ah->config.enable_ani)
780 cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
781 if (!common->ani.caldone)
782 cal_interval = min(cal_interval, (u32)short_cal_interval);
783
784 ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
785 msecs_to_jiffies(cal_interval));
786}
787
788/*******/
789/* LED */
790/*******/
791
792static void ath9k_led_blink_work(struct work_struct *work)
793{
794 struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
795 ath9k_led_blink_work.work);
796
797 if (!(priv->op_flags & OP_LED_ASSOCIATED))
798 return;
799
800 if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
801 (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
802 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
803 else
804 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
805 (priv->op_flags & OP_LED_ON) ? 1 : 0);
806
807 ieee80211_queue_delayed_work(priv->hw,
808 &priv->ath9k_led_blink_work,
809 (priv->op_flags & OP_LED_ON) ?
810 msecs_to_jiffies(priv->led_off_duration) :
811 msecs_to_jiffies(priv->led_on_duration));
812
813 priv->led_on_duration = priv->led_on_cnt ?
814 max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
815 ATH_LED_ON_DURATION_IDLE;
816 priv->led_off_duration = priv->led_off_cnt ?
817 max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
818 ATH_LED_OFF_DURATION_IDLE;
819 priv->led_on_cnt = priv->led_off_cnt = 0;
820
821 if (priv->op_flags & OP_LED_ON)
822 priv->op_flags &= ~OP_LED_ON;
823 else
824 priv->op_flags |= OP_LED_ON;
825}
826
827static void ath9k_led_brightness_work(struct work_struct *work)
828{
829 struct ath_led *led = container_of(work, struct ath_led,
830 brightness_work.work);
831 struct ath9k_htc_priv *priv = led->priv;
832
833 switch (led->brightness) {
834 case LED_OFF:
835 if (led->led_type == ATH_LED_ASSOC ||
836 led->led_type == ATH_LED_RADIO) {
837 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
838 (led->led_type == ATH_LED_RADIO));
839 priv->op_flags &= ~OP_LED_ASSOCIATED;
840 if (led->led_type == ATH_LED_RADIO)
841 priv->op_flags &= ~OP_LED_ON;
842 } else {
843 priv->led_off_cnt++;
844 }
845 break;
846 case LED_FULL:
847 if (led->led_type == ATH_LED_ASSOC) {
848 priv->op_flags |= OP_LED_ASSOCIATED;
849 ieee80211_queue_delayed_work(priv->hw,
850 &priv->ath9k_led_blink_work, 0);
851 } else if (led->led_type == ATH_LED_RADIO) {
852 ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
853 priv->op_flags |= OP_LED_ON;
854 } else {
855 priv->led_on_cnt++;
856 }
857 break;
858 default:
859 break;
860 }
861}
862
863static void ath9k_led_brightness(struct led_classdev *led_cdev,
864 enum led_brightness brightness)
865{
866 struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
867 struct ath9k_htc_priv *priv = led->priv;
868
869 led->brightness = brightness;
870 if (!(priv->op_flags & OP_LED_DEINIT))
871 ieee80211_queue_delayed_work(priv->hw,
872 &led->brightness_work, 0);
873}
874
875static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
876{
877 cancel_delayed_work_sync(&priv->radio_led.brightness_work);
878 cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
879 cancel_delayed_work_sync(&priv->tx_led.brightness_work);
880 cancel_delayed_work_sync(&priv->rx_led.brightness_work);
881}
882
883static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
884 char *trigger)
885{
886 int ret;
887
888 led->priv = priv;
889 led->led_cdev.name = led->name;
890 led->led_cdev.default_trigger = trigger;
891 led->led_cdev.brightness_set = ath9k_led_brightness;
892
893 ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
894 if (ret)
895 ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
896 "Failed to register led:%s", led->name);
897 else
898 led->registered = 1;
899
900 INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
901
902 return ret;
903}
904
905static void ath9k_unregister_led(struct ath_led *led)
906{
907 if (led->registered) {
908 led_classdev_unregister(&led->led_cdev);
909 led->registered = 0;
910 }
911}
912
913void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
914{
915 priv->op_flags |= OP_LED_DEINIT;
916 ath9k_unregister_led(&priv->assoc_led);
917 priv->op_flags &= ~OP_LED_ASSOCIATED;
918 ath9k_unregister_led(&priv->tx_led);
919 ath9k_unregister_led(&priv->rx_led);
920 ath9k_unregister_led(&priv->radio_led);
Sujithfb9987d2010-03-17 14:25:25 +0530921}
922
923void ath9k_init_leds(struct ath9k_htc_priv *priv)
924{
925 char *trigger;
926 int ret;
927
928 if (AR_SREV_9287(priv->ah))
929 priv->ah->led_pin = ATH_LED_PIN_9287;
930 else if (AR_SREV_9271(priv->ah))
931 priv->ah->led_pin = ATH_LED_PIN_9271;
Sujith88c1f4f2010-06-30 14:46:31 +0530932 else if (AR_DEVID_7010(priv->ah))
933 priv->ah->led_pin = ATH_LED_PIN_7010;
Sujithfb9987d2010-03-17 14:25:25 +0530934 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};