xref: /linux/drivers/net/wireless/ath/ath9k/htc_drv_main.c (revision 0730d114194364d078dbd0cfce708e8c67dccdfb)
1fb9987d0SSujith /*
2fb9987d0SSujith  * Copyright (c) 2010 Atheros Communications Inc.
3fb9987d0SSujith  *
4fb9987d0SSujith  * Permission to use, copy, modify, and/or distribute this software for any
5fb9987d0SSujith  * purpose with or without fee is hereby granted, provided that the above
6fb9987d0SSujith  * copyright notice and this permission notice appear in all copies.
7fb9987d0SSujith  *
8fb9987d0SSujith  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9fb9987d0SSujith  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10fb9987d0SSujith  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11fb9987d0SSujith  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12fb9987d0SSujith  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13fb9987d0SSujith  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14fb9987d0SSujith  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15fb9987d0SSujith  */
16fb9987d0SSujith 
17fb9987d0SSujith #include "htc.h"
18fb9987d0SSujith 
19fb9987d0SSujith #ifdef CONFIG_ATH9K_HTC_DEBUGFS
20fb9987d0SSujith static struct dentry *ath9k_debugfs_root;
21fb9987d0SSujith #endif
22fb9987d0SSujith 
23fb9987d0SSujith /*************/
24fb9987d0SSujith /* Utilities */
25fb9987d0SSujith /*************/
26fb9987d0SSujith 
27fb9987d0SSujith static void ath_update_txpow(struct ath9k_htc_priv *priv)
28fb9987d0SSujith {
29fb9987d0SSujith 	struct ath_hw *ah = priv->ah;
30fb9987d0SSujith 	u32 txpow;
31fb9987d0SSujith 
32fb9987d0SSujith 	if (priv->curtxpow != priv->txpowlimit) {
33fb9987d0SSujith 		ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit);
34fb9987d0SSujith 		/* read back in case value is clamped */
35fb9987d0SSujith 		ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
36fb9987d0SSujith 		priv->curtxpow = txpow;
37fb9987d0SSujith 	}
38fb9987d0SSujith }
39fb9987d0SSujith 
40fb9987d0SSujith /* HACK Alert: Use 11NG for 2.4, use 11NA for 5 */
41fb9987d0SSujith static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
42fb9987d0SSujith 					      struct ath9k_channel *ichan)
43fb9987d0SSujith {
44fb9987d0SSujith 	enum htc_phymode mode;
45fb9987d0SSujith 
46fb9987d0SSujith 	mode = HTC_MODE_AUTO;
47fb9987d0SSujith 
48fb9987d0SSujith 	switch (ichan->chanmode) {
49fb9987d0SSujith 	case CHANNEL_G:
50fb9987d0SSujith 	case CHANNEL_G_HT20:
51fb9987d0SSujith 	case CHANNEL_G_HT40PLUS:
52fb9987d0SSujith 	case CHANNEL_G_HT40MINUS:
53fb9987d0SSujith 		mode = HTC_MODE_11NG;
54fb9987d0SSujith 		break;
55fb9987d0SSujith 	case CHANNEL_A:
56fb9987d0SSujith 	case CHANNEL_A_HT20:
57fb9987d0SSujith 	case CHANNEL_A_HT40PLUS:
58fb9987d0SSujith 	case CHANNEL_A_HT40MINUS:
59fb9987d0SSujith 		mode = HTC_MODE_11NA;
60fb9987d0SSujith 		break;
61fb9987d0SSujith 	default:
62fb9987d0SSujith 		break;
63fb9987d0SSujith 	}
64fb9987d0SSujith 
65fb9987d0SSujith 	return mode;
66fb9987d0SSujith }
67fb9987d0SSujith 
68bde748a4SVivek Natarajan static bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
69bde748a4SVivek Natarajan 			       enum ath9k_power_mode mode)
70bde748a4SVivek Natarajan {
71bde748a4SVivek Natarajan 	bool ret;
72bde748a4SVivek Natarajan 
73bde748a4SVivek Natarajan 	mutex_lock(&priv->htc_pm_lock);
74bde748a4SVivek Natarajan 	ret = ath9k_hw_setpower(priv->ah, mode);
75bde748a4SVivek Natarajan 	mutex_unlock(&priv->htc_pm_lock);
76bde748a4SVivek Natarajan 
77bde748a4SVivek Natarajan 	return ret;
78bde748a4SVivek Natarajan }
79bde748a4SVivek Natarajan 
80bde748a4SVivek Natarajan void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv)
81bde748a4SVivek Natarajan {
82bde748a4SVivek Natarajan 	mutex_lock(&priv->htc_pm_lock);
83bde748a4SVivek Natarajan 	if (++priv->ps_usecount != 1)
84bde748a4SVivek Natarajan 		goto unlock;
85bde748a4SVivek Natarajan 	ath9k_hw_setpower(priv->ah, ATH9K_PM_AWAKE);
86bde748a4SVivek Natarajan 
87bde748a4SVivek Natarajan unlock:
88bde748a4SVivek Natarajan 	mutex_unlock(&priv->htc_pm_lock);
89bde748a4SVivek Natarajan }
90bde748a4SVivek Natarajan 
91bde748a4SVivek Natarajan void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv)
92bde748a4SVivek Natarajan {
93bde748a4SVivek Natarajan 	mutex_lock(&priv->htc_pm_lock);
94bde748a4SVivek Natarajan 	if (--priv->ps_usecount != 0)
95bde748a4SVivek Natarajan 		goto unlock;
96bde748a4SVivek Natarajan 
978a8572a8SVivek Natarajan 	if (priv->ps_idle)
988a8572a8SVivek Natarajan 		ath9k_hw_setpower(priv->ah, ATH9K_PM_FULL_SLEEP);
998a8572a8SVivek Natarajan 	else if (priv->ps_enabled)
100bde748a4SVivek Natarajan 		ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP);
1018a8572a8SVivek Natarajan 
102bde748a4SVivek Natarajan unlock:
103bde748a4SVivek Natarajan 	mutex_unlock(&priv->htc_pm_lock);
104bde748a4SVivek Natarajan }
105bde748a4SVivek Natarajan 
106bde748a4SVivek Natarajan void ath9k_ps_work(struct work_struct *work)
107bde748a4SVivek Natarajan {
108bde748a4SVivek Natarajan 	struct ath9k_htc_priv *priv =
109bde748a4SVivek Natarajan 		container_of(work, struct ath9k_htc_priv,
110bde748a4SVivek Natarajan 			     ps_work);
111bde748a4SVivek Natarajan 	ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
112bde748a4SVivek Natarajan 
113bde748a4SVivek Natarajan 	/* The chip wakes up after receiving the first beacon
114bde748a4SVivek Natarajan 	   while network sleep is enabled. For the driver to
115bde748a4SVivek Natarajan 	   be in sync with the hw, set the chip to awake and
116bde748a4SVivek Natarajan 	   only then set it to sleep.
117bde748a4SVivek Natarajan 	 */
118bde748a4SVivek Natarajan 	ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
119bde748a4SVivek Natarajan }
120bde748a4SVivek Natarajan 
121fb9987d0SSujith static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
122fb9987d0SSujith 				 struct ieee80211_hw *hw,
123fb9987d0SSujith 				 struct ath9k_channel *hchan)
124fb9987d0SSujith {
125fb9987d0SSujith 	struct ath_hw *ah = priv->ah;
126fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(ah);
127fb9987d0SSujith 	struct ieee80211_conf *conf = &common->hw->conf;
128fb9987d0SSujith 	bool fastcc = true;
129fb9987d0SSujith 	struct ieee80211_channel *channel = hw->conf.channel;
130fb9987d0SSujith 	enum htc_phymode mode;
1317f1f5a00SSujith 	__be16 htc_mode;
132fb9987d0SSujith 	u8 cmd_rsp;
133fb9987d0SSujith 	int ret;
134fb9987d0SSujith 
135fb9987d0SSujith 	if (priv->op_flags & OP_INVALID)
136fb9987d0SSujith 		return -EIO;
137fb9987d0SSujith 
138fb9987d0SSujith 	if (priv->op_flags & OP_FULL_RESET)
139fb9987d0SSujith 		fastcc = false;
140fb9987d0SSujith 
141fb9987d0SSujith 	/* Fiddle around with fastcc later on, for now just use full reset */
142fb9987d0SSujith 	fastcc = false;
143bde748a4SVivek Natarajan 	ath9k_htc_ps_wakeup(priv);
144fb9987d0SSujith 	htc_stop(priv->htc);
145fb9987d0SSujith 	WMI_CMD(WMI_DISABLE_INTR_CMDID);
146fb9987d0SSujith 	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
147fb9987d0SSujith 	WMI_CMD(WMI_STOP_RECV_CMDID);
148fb9987d0SSujith 
149fb9987d0SSujith 	ath_print(common, ATH_DBG_CONFIG,
150fb9987d0SSujith 		  "(%u MHz) -> (%u MHz), HT: %d, HT40: %d\n",
151fb9987d0SSujith 		  priv->ah->curchan->channel,
152fb9987d0SSujith 		  channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf));
153fb9987d0SSujith 
154fb9987d0SSujith 	ret = ath9k_hw_reset(ah, hchan, fastcc);
155fb9987d0SSujith 	if (ret) {
156fb9987d0SSujith 		ath_print(common, ATH_DBG_FATAL,
157fb9987d0SSujith 			  "Unable to reset channel (%u Mhz) "
158fb9987d0SSujith 			  "reset status %d\n", channel->center_freq, ret);
159fb9987d0SSujith 		goto err;
160fb9987d0SSujith 	}
161fb9987d0SSujith 
162fb9987d0SSujith 	ath_update_txpow(priv);
163fb9987d0SSujith 
164fb9987d0SSujith 	WMI_CMD(WMI_START_RECV_CMDID);
165fb9987d0SSujith 	if (ret)
166fb9987d0SSujith 		goto err;
167fb9987d0SSujith 
168fb9987d0SSujith 	ath9k_host_rx_init(priv);
169fb9987d0SSujith 
170fb9987d0SSujith 	mode = ath9k_htc_get_curmode(priv, hchan);
171fb9987d0SSujith 	htc_mode = cpu_to_be16(mode);
172fb9987d0SSujith 	WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
173fb9987d0SSujith 	if (ret)
174fb9987d0SSujith 		goto err;
175fb9987d0SSujith 
176fb9987d0SSujith 	WMI_CMD(WMI_ENABLE_INTR_CMDID);
177fb9987d0SSujith 	if (ret)
178fb9987d0SSujith 		goto err;
179fb9987d0SSujith 
180fb9987d0SSujith 	htc_start(priv->htc);
181fb9987d0SSujith 
182fb9987d0SSujith 	priv->op_flags &= ~OP_FULL_RESET;
183fb9987d0SSujith err:
184bde748a4SVivek Natarajan 	ath9k_htc_ps_restore(priv);
185fb9987d0SSujith 	return ret;
186fb9987d0SSujith }
187fb9987d0SSujith 
188fb9987d0SSujith static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
189fb9987d0SSujith {
190fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
191fb9987d0SSujith 	struct ath9k_htc_target_vif hvif;
192fb9987d0SSujith 	int ret = 0;
193fb9987d0SSujith 	u8 cmd_rsp;
194fb9987d0SSujith 
195fb9987d0SSujith 	if (priv->nvifs > 0)
196fb9987d0SSujith 		return -ENOBUFS;
197fb9987d0SSujith 
198fb9987d0SSujith 	memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
199fb9987d0SSujith 	memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
200fb9987d0SSujith 
201fb9987d0SSujith 	hvif.opmode = cpu_to_be32(HTC_M_MONITOR);
202fb9987d0SSujith 	priv->ah->opmode = NL80211_IFTYPE_MONITOR;
203fb9987d0SSujith 	hvif.index = priv->nvifs;
204fb9987d0SSujith 
205fb9987d0SSujith 	WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
206fb9987d0SSujith 	if (ret)
207fb9987d0SSujith 		return ret;
208fb9987d0SSujith 
209fb9987d0SSujith 	priv->nvifs++;
210fb9987d0SSujith 	return 0;
211fb9987d0SSujith }
212fb9987d0SSujith 
213fb9987d0SSujith static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
214fb9987d0SSujith {
215fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
216fb9987d0SSujith 	struct ath9k_htc_target_vif hvif;
217fb9987d0SSujith 	int ret = 0;
218fb9987d0SSujith 	u8 cmd_rsp;
219fb9987d0SSujith 
220fb9987d0SSujith 	memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
221fb9987d0SSujith 	memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
222fb9987d0SSujith 	hvif.index = 0; /* Should do for now */
223fb9987d0SSujith 	WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
224fb9987d0SSujith 	priv->nvifs--;
225fb9987d0SSujith 
226fb9987d0SSujith 	return ret;
227fb9987d0SSujith }
228fb9987d0SSujith 
229fb9987d0SSujith static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
230fb9987d0SSujith 				 struct ieee80211_vif *vif,
231fb9987d0SSujith 				 struct ieee80211_sta *sta)
232fb9987d0SSujith {
233fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
234fb9987d0SSujith 	struct ath9k_htc_target_sta tsta;
235fb9987d0SSujith 	struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
236fb9987d0SSujith 	struct ath9k_htc_sta *ista;
237fb9987d0SSujith 	int ret;
238fb9987d0SSujith 	u8 cmd_rsp;
239fb9987d0SSujith 
240fb9987d0SSujith 	if (priv->nstations >= ATH9K_HTC_MAX_STA)
241fb9987d0SSujith 		return -ENOBUFS;
242fb9987d0SSujith 
243fb9987d0SSujith 	memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta));
244fb9987d0SSujith 
245fb9987d0SSujith 	if (sta) {
246fb9987d0SSujith 		ista = (struct ath9k_htc_sta *) sta->drv_priv;
247fb9987d0SSujith 		memcpy(&tsta.macaddr, sta->addr, ETH_ALEN);
248fb9987d0SSujith 		memcpy(&tsta.bssid, common->curbssid, ETH_ALEN);
249fb9987d0SSujith 		tsta.associd = common->curaid;
250fb9987d0SSujith 		tsta.is_vif_sta = 0;
251fb9987d0SSujith 		tsta.valid = true;
252fb9987d0SSujith 		ista->index = priv->nstations;
253fb9987d0SSujith 	} else {
254fb9987d0SSujith 		memcpy(&tsta.macaddr, vif->addr, ETH_ALEN);
255fb9987d0SSujith 		tsta.is_vif_sta = 1;
256fb9987d0SSujith 	}
257fb9987d0SSujith 
258fb9987d0SSujith 	tsta.sta_index = priv->nstations;
259fb9987d0SSujith 	tsta.vif_index = avp->index;
260fb9987d0SSujith 	tsta.maxampdu = 0xffff;
261fb9987d0SSujith 	if (sta && sta->ht_cap.ht_supported)
262fb9987d0SSujith 		tsta.flags = cpu_to_be16(ATH_HTC_STA_HT);
263fb9987d0SSujith 
264fb9987d0SSujith 	WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
265fb9987d0SSujith 	if (ret) {
266fb9987d0SSujith 		if (sta)
267fb9987d0SSujith 			ath_print(common, ATH_DBG_FATAL,
268fb9987d0SSujith 			  "Unable to add station entry for: %pM\n", sta->addr);
269fb9987d0SSujith 		return ret;
270fb9987d0SSujith 	}
271fb9987d0SSujith 
272fb9987d0SSujith 	if (sta)
273fb9987d0SSujith 		ath_print(common, ATH_DBG_CONFIG,
274fb9987d0SSujith 			  "Added a station entry for: %pM (idx: %d)\n",
275fb9987d0SSujith 			  sta->addr, tsta.sta_index);
276fb9987d0SSujith 
277fb9987d0SSujith 	priv->nstations++;
278fb9987d0SSujith 	return 0;
279fb9987d0SSujith }
280fb9987d0SSujith 
281fb9987d0SSujith static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
282fb9987d0SSujith 				    struct ieee80211_vif *vif,
283fb9987d0SSujith 				    struct ieee80211_sta *sta)
284fb9987d0SSujith {
285fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
286fb9987d0SSujith 	struct ath9k_htc_sta *ista;
287fb9987d0SSujith 	int ret;
288fb9987d0SSujith 	u8 cmd_rsp, sta_idx;
289fb9987d0SSujith 
290fb9987d0SSujith 	if (sta) {
291fb9987d0SSujith 		ista = (struct ath9k_htc_sta *) sta->drv_priv;
292fb9987d0SSujith 		sta_idx = ista->index;
293fb9987d0SSujith 	} else {
294fb9987d0SSujith 		sta_idx = 0;
295fb9987d0SSujith 	}
296fb9987d0SSujith 
297fb9987d0SSujith 	WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx);
298fb9987d0SSujith 	if (ret) {
299fb9987d0SSujith 		if (sta)
300fb9987d0SSujith 			ath_print(common, ATH_DBG_FATAL,
301fb9987d0SSujith 			  "Unable to remove station entry for: %pM\n",
302fb9987d0SSujith 			  sta->addr);
303fb9987d0SSujith 		return ret;
304fb9987d0SSujith 	}
305fb9987d0SSujith 
306fb9987d0SSujith 	if (sta)
307fb9987d0SSujith 		ath_print(common, ATH_DBG_CONFIG,
308fb9987d0SSujith 			  "Removed a station entry for: %pM (idx: %d)\n",
309fb9987d0SSujith 			  sta->addr, sta_idx);
310fb9987d0SSujith 
311fb9987d0SSujith 	priv->nstations--;
312fb9987d0SSujith 	return 0;
313fb9987d0SSujith }
314fb9987d0SSujith 
315fb9987d0SSujith static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
316fb9987d0SSujith {
317fb9987d0SSujith 	struct ath9k_htc_cap_target tcap;
318fb9987d0SSujith 	int ret;
319fb9987d0SSujith 	u8 cmd_rsp;
320fb9987d0SSujith 
321fb9987d0SSujith 	memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target));
322fb9987d0SSujith 
323fb9987d0SSujith 	/* FIXME: Values are hardcoded */
324fb9987d0SSujith 	tcap.flags = 0x240c40;
325fb9987d0SSujith 	tcap.flags_ext = 0x80601000;
326fb9987d0SSujith 	tcap.ampdu_limit = 0xffff0000;
327fb9987d0SSujith 	tcap.ampdu_subframes = 20;
328fb9987d0SSujith 	tcap.tx_chainmask_legacy = 1;
329fb9987d0SSujith 	tcap.protmode = 1;
330fb9987d0SSujith 	tcap.tx_chainmask = 1;
331fb9987d0SSujith 
332fb9987d0SSujith 	WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap);
333fb9987d0SSujith 
334fb9987d0SSujith 	return ret;
335fb9987d0SSujith }
336fb9987d0SSujith 
337fb9987d0SSujith static int ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
338fb9987d0SSujith 				 struct ieee80211_vif *vif,
339fb9987d0SSujith 				 struct ieee80211_sta *sta)
340fb9987d0SSujith {
341fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
342fb9987d0SSujith 	struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
343fb9987d0SSujith 	struct ieee80211_supported_band *sband;
344fb9987d0SSujith 	struct ath9k_htc_target_rate trate;
345fb9987d0SSujith 	u32 caps = 0;
346fb9987d0SSujith 	u8 cmd_rsp;
347fb9987d0SSujith 	int i, j, ret;
348fb9987d0SSujith 
349fb9987d0SSujith 	memset(&trate, 0, sizeof(trate));
350fb9987d0SSujith 
351fb9987d0SSujith 	/* Only 2GHz is supported */
352fb9987d0SSujith 	sband = priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
353fb9987d0SSujith 
354fb9987d0SSujith 	for (i = 0, j = 0; i < sband->n_bitrates; i++) {
355fb9987d0SSujith 		if (sta->supp_rates[sband->band] & BIT(i)) {
356fb9987d0SSujith 			priv->tgt_rate.rates.legacy_rates.rs_rates[j]
357fb9987d0SSujith 				= (sband->bitrates[i].bitrate * 2) / 10;
358fb9987d0SSujith 			j++;
359fb9987d0SSujith 		}
360fb9987d0SSujith 	}
361fb9987d0SSujith 	priv->tgt_rate.rates.legacy_rates.rs_nrates = j;
362fb9987d0SSujith 
363fb9987d0SSujith 	if (sta->ht_cap.ht_supported) {
364fb9987d0SSujith 		for (i = 0, j = 0; i < 77; i++) {
365fb9987d0SSujith 			if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
366fb9987d0SSujith 				priv->tgt_rate.rates.ht_rates.rs_rates[j++] = i;
367fb9987d0SSujith 			if (j == ATH_HTC_RATE_MAX)
368fb9987d0SSujith 				break;
369fb9987d0SSujith 		}
370fb9987d0SSujith 		priv->tgt_rate.rates.ht_rates.rs_nrates = j;
371fb9987d0SSujith 
372fb9987d0SSujith 		caps = WLAN_RC_HT_FLAG;
373fb9987d0SSujith 		if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
374fb9987d0SSujith 			caps |= WLAN_RC_40_FLAG;
375fb9987d0SSujith 		if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
376fb9987d0SSujith 			caps |= WLAN_RC_SGI_FLAG;
377fb9987d0SSujith 
378fb9987d0SSujith 	}
379fb9987d0SSujith 
380fb9987d0SSujith 	priv->tgt_rate.sta_index = ista->index;
381fb9987d0SSujith 	priv->tgt_rate.isnew = 1;
382fb9987d0SSujith 	trate = priv->tgt_rate;
3837f1f5a00SSujith 	priv->tgt_rate.capflags = cpu_to_be32(caps);
384fb9987d0SSujith 	trate.capflags = cpu_to_be32(caps);
385fb9987d0SSujith 
386fb9987d0SSujith 	WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
387fb9987d0SSujith 	if (ret) {
388fb9987d0SSujith 		ath_print(common, ATH_DBG_FATAL,
389fb9987d0SSujith 			  "Unable to initialize Rate information on target\n");
390fb9987d0SSujith 		return ret;
391fb9987d0SSujith 	}
392fb9987d0SSujith 
393fb9987d0SSujith 	ath_print(common, ATH_DBG_CONFIG,
394fb9987d0SSujith 		  "Updated target STA: %pM (caps: 0x%x)\n", sta->addr, caps);
395fb9987d0SSujith 	return 0;
396fb9987d0SSujith }
397fb9987d0SSujith 
398fb9987d0SSujith static bool check_rc_update(struct ieee80211_hw *hw, bool *cw40)
399fb9987d0SSujith {
400fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
401fb9987d0SSujith 	struct ieee80211_conf *conf = &hw->conf;
402fb9987d0SSujith 
403fb9987d0SSujith 	if (!conf_is_ht(conf))
404fb9987d0SSujith 		return false;
405fb9987d0SSujith 
406fb9987d0SSujith 	if (!(priv->op_flags & OP_ASSOCIATED) ||
407fb9987d0SSujith 	    (priv->op_flags & OP_SCANNING))
408fb9987d0SSujith 		return false;
409fb9987d0SSujith 
410fb9987d0SSujith 	if (conf_is_ht40(conf)) {
411fb9987d0SSujith 		if (priv->ah->curchan->chanmode &
412fb9987d0SSujith 			(CHANNEL_HT40PLUS | CHANNEL_HT40MINUS)) {
413fb9987d0SSujith 			return false;
414fb9987d0SSujith 		} else {
415fb9987d0SSujith 			*cw40 = true;
416fb9987d0SSujith 			return true;
417fb9987d0SSujith 		}
418fb9987d0SSujith 	} else {  /* ht20 */
419fb9987d0SSujith 		if (priv->ah->curchan->chanmode & CHANNEL_HT20)
420fb9987d0SSujith 			return false;
421fb9987d0SSujith 		else
422fb9987d0SSujith 			return true;
423fb9987d0SSujith 	}
424fb9987d0SSujith }
425fb9987d0SSujith 
426fb9987d0SSujith static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40)
427fb9987d0SSujith {
428fb9987d0SSujith 	struct ath9k_htc_target_rate trate;
429fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
430fb9987d0SSujith 	int ret;
4317f1f5a00SSujith 	u32 caps = be32_to_cpu(priv->tgt_rate.capflags);
432fb9987d0SSujith 	u8 cmd_rsp;
433fb9987d0SSujith 
434fb9987d0SSujith 	memset(&trate, 0, sizeof(trate));
435fb9987d0SSujith 
436fb9987d0SSujith 	trate = priv->tgt_rate;
437fb9987d0SSujith 
438fb9987d0SSujith 	if (is_cw40)
4397f1f5a00SSujith 		caps |= WLAN_RC_40_FLAG;
440fb9987d0SSujith 	else
4417f1f5a00SSujith 		caps &= ~WLAN_RC_40_FLAG;
442fb9987d0SSujith 
4437f1f5a00SSujith 	priv->tgt_rate.capflags = cpu_to_be32(caps);
4447f1f5a00SSujith 	trate.capflags = cpu_to_be32(caps);
445fb9987d0SSujith 
446fb9987d0SSujith 	WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
447fb9987d0SSujith 	if (ret) {
448fb9987d0SSujith 		ath_print(common, ATH_DBG_FATAL,
449fb9987d0SSujith 			  "Unable to update Rate information on target\n");
450fb9987d0SSujith 		return;
451fb9987d0SSujith 	}
452fb9987d0SSujith 
453fb9987d0SSujith 	ath_print(common, ATH_DBG_CONFIG, "Rate control updated with "
454fb9987d0SSujith 		  "caps:0x%x on target\n", priv->tgt_rate.capflags);
455fb9987d0SSujith }
456fb9987d0SSujith 
457fb9987d0SSujith static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
458fb9987d0SSujith 			       struct ieee80211_vif *vif,
459fb9987d0SSujith 			       u8 *sta_addr, u8 tid, bool oper)
460fb9987d0SSujith {
461fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
462fb9987d0SSujith 	struct ath9k_htc_target_aggr aggr;
463fb9987d0SSujith 	struct ieee80211_sta *sta = NULL;
464277a64d1SDan Carpenter 	struct ath9k_htc_sta *ista;
465fb9987d0SSujith 	int ret = 0;
466fb9987d0SSujith 	u8 cmd_rsp;
467fb9987d0SSujith 
468*0730d114SDan Carpenter 	if (tid >= ATH9K_HTC_MAX_TID)
469fb9987d0SSujith 		return -EINVAL;
470fb9987d0SSujith 
471fb9987d0SSujith 	memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
472fb9987d0SSujith 
473ef98c3cdSSujith 	rcu_read_lock();
474ef98c3cdSSujith 
475ef98c3cdSSujith 	/* Check if we are able to retrieve the station */
476ef98c3cdSSujith 	sta = ieee80211_find_sta(vif, sta_addr);
477ef98c3cdSSujith 	if (!sta) {
478fb9987d0SSujith 		rcu_read_unlock();
479ef98c3cdSSujith 		return -EINVAL;
480ef98c3cdSSujith 	}
481ef98c3cdSSujith 
482ef98c3cdSSujith 	ista = (struct ath9k_htc_sta *) sta->drv_priv;
483fb9987d0SSujith 
484fb9987d0SSujith 	if (oper)
485fb9987d0SSujith 		ista->tid_state[tid] = AGGR_START;
486fb9987d0SSujith 	else
487fb9987d0SSujith 		ista->tid_state[tid] = AGGR_STOP;
488fb9987d0SSujith 
489ef98c3cdSSujith 	aggr.sta_index = ista->index;
490ef98c3cdSSujith 
491ef98c3cdSSujith 	rcu_read_unlock();
492ef98c3cdSSujith 
493ef98c3cdSSujith 	aggr.tidno = tid;
494ef98c3cdSSujith 	aggr.aggr_enable = oper;
495ef98c3cdSSujith 
496fb9987d0SSujith 	WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
497fb9987d0SSujith 	if (ret)
498fb9987d0SSujith 		ath_print(common, ATH_DBG_CONFIG,
499fb9987d0SSujith 			  "Unable to %s TX aggregation for (%pM, %d)\n",
500fb9987d0SSujith 			  (oper) ? "start" : "stop", sta->addr, tid);
501fb9987d0SSujith 	else
502fb9987d0SSujith 		ath_print(common, ATH_DBG_CONFIG,
503fb9987d0SSujith 			  "%s aggregation for (%pM, %d)\n",
504fb9987d0SSujith 			  (oper) ? "Starting" : "Stopping", sta->addr, tid);
505fb9987d0SSujith 
506fb9987d0SSujith 	return ret;
507fb9987d0SSujith }
508fb9987d0SSujith 
509fb9987d0SSujith void ath9k_htc_aggr_work(struct work_struct *work)
510fb9987d0SSujith {
511fb9987d0SSujith 	int ret = 0;
512fb9987d0SSujith 	struct ath9k_htc_priv *priv =
513fb9987d0SSujith 		container_of(work, struct ath9k_htc_priv,
514fb9987d0SSujith 			     ath9k_aggr_work.work);
515fb9987d0SSujith 	struct ath9k_htc_aggr_work *wk = &priv->aggr_work;
516fb9987d0SSujith 
517fb9987d0SSujith 	mutex_lock(&wk->mutex);
518fb9987d0SSujith 
519fb9987d0SSujith 	switch (wk->action) {
520fb9987d0SSujith 	case IEEE80211_AMPDU_TX_START:
521fb9987d0SSujith 		ret = ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
522fb9987d0SSujith 					  wk->tid, true);
523fb9987d0SSujith 		if (!ret)
524fb9987d0SSujith 			ieee80211_start_tx_ba_cb(wk->vif, wk->sta_addr,
525fb9987d0SSujith 						 wk->tid);
526fb9987d0SSujith 		break;
527fb9987d0SSujith 	case IEEE80211_AMPDU_TX_STOP:
528fb9987d0SSujith 		ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
529fb9987d0SSujith 				    wk->tid, false);
530fb9987d0SSujith 		ieee80211_stop_tx_ba_cb(wk->vif, wk->sta_addr, wk->tid);
531fb9987d0SSujith 		break;
532fb9987d0SSujith 	default:
533fb9987d0SSujith 		ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
534fb9987d0SSujith 			  "Unknown AMPDU action\n");
535fb9987d0SSujith 	}
536fb9987d0SSujith 
537fb9987d0SSujith 	mutex_unlock(&wk->mutex);
538fb9987d0SSujith }
539fb9987d0SSujith 
540fb9987d0SSujith /*********/
541fb9987d0SSujith /* DEBUG */
542fb9987d0SSujith /*********/
543fb9987d0SSujith 
544fb9987d0SSujith #ifdef CONFIG_ATH9K_HTC_DEBUGFS
545fb9987d0SSujith 
546fb9987d0SSujith static int ath9k_debugfs_open(struct inode *inode, struct file *file)
547fb9987d0SSujith {
548fb9987d0SSujith 	file->private_data = inode->i_private;
549fb9987d0SSujith 	return 0;
550fb9987d0SSujith }
551fb9987d0SSujith 
552fb9987d0SSujith static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
553fb9987d0SSujith 				   size_t count, loff_t *ppos)
554fb9987d0SSujith {
555fb9987d0SSujith 	struct ath9k_htc_priv *priv =
556fb9987d0SSujith 		(struct ath9k_htc_priv *) file->private_data;
557fb9987d0SSujith 	struct ath9k_htc_target_stats cmd_rsp;
558fb9987d0SSujith 	char buf[512];
559fb9987d0SSujith 	unsigned int len = 0;
560fb9987d0SSujith 	int ret = 0;
561fb9987d0SSujith 
562fb9987d0SSujith 	memset(&cmd_rsp, 0, sizeof(cmd_rsp));
563fb9987d0SSujith 
564fb9987d0SSujith 	WMI_CMD(WMI_TGT_STATS_CMDID);
565fb9987d0SSujith 	if (ret)
566fb9987d0SSujith 		return -EINVAL;
567fb9987d0SSujith 
568fb9987d0SSujith 
569fb9987d0SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
570fb9987d0SSujith 			"%19s : %10u\n", "TX Short Retries",
571fb9987d0SSujith 			be32_to_cpu(cmd_rsp.tx_shortretry));
572fb9987d0SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
573fb9987d0SSujith 			"%19s : %10u\n", "TX Long Retries",
574fb9987d0SSujith 			be32_to_cpu(cmd_rsp.tx_longretry));
575fb9987d0SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
576fb9987d0SSujith 			"%19s : %10u\n", "TX Xretries",
577fb9987d0SSujith 			be32_to_cpu(cmd_rsp.tx_xretries));
578fb9987d0SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
579fb9987d0SSujith 			"%19s : %10u\n", "TX Unaggr. Xretries",
580fb9987d0SSujith 			be32_to_cpu(cmd_rsp.ht_txunaggr_xretry));
581fb9987d0SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
582fb9987d0SSujith 			"%19s : %10u\n", "TX Xretries (HT)",
583fb9987d0SSujith 			be32_to_cpu(cmd_rsp.ht_tx_xretries));
584fb9987d0SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
585fb9987d0SSujith 			"%19s : %10u\n", "TX Rate", priv->debug.txrate);
586fb9987d0SSujith 
587fb9987d0SSujith 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
588fb9987d0SSujith }
589fb9987d0SSujith 
590fb9987d0SSujith static const struct file_operations fops_tgt_stats = {
591fb9987d0SSujith 	.read = read_file_tgt_stats,
592fb9987d0SSujith 	.open = ath9k_debugfs_open,
593fb9987d0SSujith 	.owner = THIS_MODULE
594fb9987d0SSujith };
595fb9987d0SSujith 
596fb9987d0SSujith static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
597fb9987d0SSujith 			      size_t count, loff_t *ppos)
598fb9987d0SSujith {
599fb9987d0SSujith 	struct ath9k_htc_priv *priv =
600fb9987d0SSujith 		(struct ath9k_htc_priv *) file->private_data;
601fb9987d0SSujith 	char buf[512];
602fb9987d0SSujith 	unsigned int len = 0;
603fb9987d0SSujith 
604fb9987d0SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
605fb9987d0SSujith 			"%20s : %10u\n", "Buffers queued",
606fb9987d0SSujith 			priv->debug.tx_stats.buf_queued);
607fb9987d0SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
608fb9987d0SSujith 			"%20s : %10u\n", "Buffers completed",
609fb9987d0SSujith 			priv->debug.tx_stats.buf_completed);
610fb9987d0SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
611fb9987d0SSujith 			"%20s : %10u\n", "SKBs queued",
612fb9987d0SSujith 			priv->debug.tx_stats.skb_queued);
613fb9987d0SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
614fb9987d0SSujith 			"%20s : %10u\n", "SKBs completed",
615fb9987d0SSujith 			priv->debug.tx_stats.skb_completed);
616eac8e385SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
617eac8e385SSujith 			"%20s : %10u\n", "SKBs dropped",
618eac8e385SSujith 			priv->debug.tx_stats.skb_dropped);
619fb9987d0SSujith 
620fb9987d0SSujith 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
621fb9987d0SSujith }
622fb9987d0SSujith 
623fb9987d0SSujith static const struct file_operations fops_xmit = {
624fb9987d0SSujith 	.read = read_file_xmit,
625fb9987d0SSujith 	.open = ath9k_debugfs_open,
626fb9987d0SSujith 	.owner = THIS_MODULE
627fb9987d0SSujith };
628fb9987d0SSujith 
629fb9987d0SSujith static ssize_t read_file_recv(struct file *file, char __user *user_buf,
630fb9987d0SSujith 			      size_t count, loff_t *ppos)
631fb9987d0SSujith {
632fb9987d0SSujith 	struct ath9k_htc_priv *priv =
633fb9987d0SSujith 		(struct ath9k_htc_priv *) file->private_data;
634fb9987d0SSujith 	char buf[512];
635fb9987d0SSujith 	unsigned int len = 0;
636fb9987d0SSujith 
637fb9987d0SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
638fb9987d0SSujith 			"%20s : %10u\n", "SKBs allocated",
639fb9987d0SSujith 			priv->debug.rx_stats.skb_allocated);
640fb9987d0SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
641fb9987d0SSujith 			"%20s : %10u\n", "SKBs completed",
642fb9987d0SSujith 			priv->debug.rx_stats.skb_completed);
643fb9987d0SSujith 	len += snprintf(buf + len, sizeof(buf) - len,
644fb9987d0SSujith 			"%20s : %10u\n", "SKBs Dropped",
645fb9987d0SSujith 			priv->debug.rx_stats.skb_dropped);
646fb9987d0SSujith 
647fb9987d0SSujith 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
648fb9987d0SSujith }
649fb9987d0SSujith 
650fb9987d0SSujith static const struct file_operations fops_recv = {
651fb9987d0SSujith 	.read = read_file_recv,
652fb9987d0SSujith 	.open = ath9k_debugfs_open,
653fb9987d0SSujith 	.owner = THIS_MODULE
654fb9987d0SSujith };
655fb9987d0SSujith 
656e1572c5eSSujith int ath9k_htc_init_debug(struct ath_hw *ah)
657fb9987d0SSujith {
658fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(ah);
659fb9987d0SSujith 	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
660fb9987d0SSujith 
661fb9987d0SSujith 	if (!ath9k_debugfs_root)
662fb9987d0SSujith 		return -ENOENT;
663fb9987d0SSujith 
664fb9987d0SSujith 	priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy),
665fb9987d0SSujith 						     ath9k_debugfs_root);
666fb9987d0SSujith 	if (!priv->debug.debugfs_phy)
667fb9987d0SSujith 		goto err;
668fb9987d0SSujith 
669fb9987d0SSujith 	priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR,
670fb9987d0SSujith 						    priv->debug.debugfs_phy,
671fb9987d0SSujith 						    priv, &fops_tgt_stats);
672fb9987d0SSujith 	if (!priv->debug.debugfs_tgt_stats)
673fb9987d0SSujith 		goto err;
674fb9987d0SSujith 
675fb9987d0SSujith 
676fb9987d0SSujith 	priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR,
677fb9987d0SSujith 						       priv->debug.debugfs_phy,
678fb9987d0SSujith 						       priv, &fops_xmit);
679fb9987d0SSujith 	if (!priv->debug.debugfs_xmit)
680fb9987d0SSujith 		goto err;
681fb9987d0SSujith 
682fb9987d0SSujith 	priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR,
683fb9987d0SSujith 						       priv->debug.debugfs_phy,
684fb9987d0SSujith 						       priv, &fops_recv);
685fb9987d0SSujith 	if (!priv->debug.debugfs_recv)
686fb9987d0SSujith 		goto err;
687fb9987d0SSujith 
688fb9987d0SSujith 	return 0;
689fb9987d0SSujith 
690fb9987d0SSujith err:
691e1572c5eSSujith 	ath9k_htc_exit_debug(ah);
692fb9987d0SSujith 	return -ENOMEM;
693fb9987d0SSujith }
694fb9987d0SSujith 
695e1572c5eSSujith void ath9k_htc_exit_debug(struct ath_hw *ah)
696fb9987d0SSujith {
697fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(ah);
698fb9987d0SSujith 	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
699fb9987d0SSujith 
700fb9987d0SSujith 	debugfs_remove(priv->debug.debugfs_recv);
701fb9987d0SSujith 	debugfs_remove(priv->debug.debugfs_xmit);
702fb9987d0SSujith 	debugfs_remove(priv->debug.debugfs_tgt_stats);
703fb9987d0SSujith 	debugfs_remove(priv->debug.debugfs_phy);
704fb9987d0SSujith }
705fb9987d0SSujith 
706e1572c5eSSujith int ath9k_htc_debug_create_root(void)
707fb9987d0SSujith {
708fb9987d0SSujith 	ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
709fb9987d0SSujith 	if (!ath9k_debugfs_root)
710fb9987d0SSujith 		return -ENOENT;
711fb9987d0SSujith 
712fb9987d0SSujith 	return 0;
713fb9987d0SSujith }
714fb9987d0SSujith 
715e1572c5eSSujith void ath9k_htc_debug_remove_root(void)
716fb9987d0SSujith {
717fb9987d0SSujith 	debugfs_remove(ath9k_debugfs_root);
718fb9987d0SSujith 	ath9k_debugfs_root = NULL;
719fb9987d0SSujith }
720fb9987d0SSujith 
721fb9987d0SSujith #endif /* CONFIG_ATH9K_HTC_DEBUGFS */
722fb9987d0SSujith 
723fb9987d0SSujith /*******/
724fb9987d0SSujith /* ANI */
725fb9987d0SSujith /*******/
726fb9987d0SSujith 
727fb9987d0SSujith static void ath_start_ani(struct ath9k_htc_priv *priv)
728fb9987d0SSujith {
729fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
730fb9987d0SSujith 	unsigned long timestamp = jiffies_to_msecs(jiffies);
731fb9987d0SSujith 
732fb9987d0SSujith 	common->ani.longcal_timer = timestamp;
733fb9987d0SSujith 	common->ani.shortcal_timer = timestamp;
734fb9987d0SSujith 	common->ani.checkani_timer = timestamp;
735fb9987d0SSujith 
736fb9987d0SSujith 	ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
737fb9987d0SSujith 				     msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
738fb9987d0SSujith }
739fb9987d0SSujith 
740fb9987d0SSujith void ath9k_ani_work(struct work_struct *work)
741fb9987d0SSujith {
742fb9987d0SSujith 	struct ath9k_htc_priv *priv =
743fb9987d0SSujith 		container_of(work, struct ath9k_htc_priv,
744fb9987d0SSujith 			     ath9k_ani_work.work);
745fb9987d0SSujith 	struct ath_hw *ah = priv->ah;
746fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(ah);
747fb9987d0SSujith 	bool longcal = false;
748fb9987d0SSujith 	bool shortcal = false;
749fb9987d0SSujith 	bool aniflag = false;
750fb9987d0SSujith 	unsigned int timestamp = jiffies_to_msecs(jiffies);
751fb9987d0SSujith 	u32 cal_interval, short_cal_interval;
752fb9987d0SSujith 
753fb9987d0SSujith 	short_cal_interval = ATH_STA_SHORT_CALINTERVAL;
754fb9987d0SSujith 
755bde748a4SVivek Natarajan 	/* Only calibrate if awake */
756bde748a4SVivek Natarajan 	if (ah->power_mode != ATH9K_PM_AWAKE)
757bde748a4SVivek Natarajan 		goto set_timer;
758bde748a4SVivek Natarajan 
759fb9987d0SSujith 	/* Long calibration runs independently of short calibration. */
760fb9987d0SSujith 	if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
761fb9987d0SSujith 		longcal = true;
762fb9987d0SSujith 		ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
763fb9987d0SSujith 		common->ani.longcal_timer = timestamp;
764fb9987d0SSujith 	}
765fb9987d0SSujith 
766fb9987d0SSujith 	/* Short calibration applies only while caldone is false */
767fb9987d0SSujith 	if (!common->ani.caldone) {
768fb9987d0SSujith 		if ((timestamp - common->ani.shortcal_timer) >=
769fb9987d0SSujith 		    short_cal_interval) {
770fb9987d0SSujith 			shortcal = true;
771fb9987d0SSujith 			ath_print(common, ATH_DBG_ANI,
772fb9987d0SSujith 				  "shortcal @%lu\n", jiffies);
773fb9987d0SSujith 			common->ani.shortcal_timer = timestamp;
774fb9987d0SSujith 			common->ani.resetcal_timer = timestamp;
775fb9987d0SSujith 		}
776fb9987d0SSujith 	} else {
777fb9987d0SSujith 		if ((timestamp - common->ani.resetcal_timer) >=
778fb9987d0SSujith 		    ATH_RESTART_CALINTERVAL) {
779fb9987d0SSujith 			common->ani.caldone = ath9k_hw_reset_calvalid(ah);
780fb9987d0SSujith 			if (common->ani.caldone)
781fb9987d0SSujith 				common->ani.resetcal_timer = timestamp;
782fb9987d0SSujith 		}
783fb9987d0SSujith 	}
784fb9987d0SSujith 
785fb9987d0SSujith 	/* Verify whether we must check ANI */
786fb9987d0SSujith 	if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
787fb9987d0SSujith 		aniflag = true;
788fb9987d0SSujith 		common->ani.checkani_timer = timestamp;
789fb9987d0SSujith 	}
790fb9987d0SSujith 
791fb9987d0SSujith 	/* Skip all processing if there's nothing to do. */
792fb9987d0SSujith 	if (longcal || shortcal || aniflag) {
793bde748a4SVivek Natarajan 
794bde748a4SVivek Natarajan 		ath9k_htc_ps_wakeup(priv);
795bde748a4SVivek Natarajan 
796fb9987d0SSujith 		/* Call ANI routine if necessary */
797fb9987d0SSujith 		if (aniflag)
798fb9987d0SSujith 			ath9k_hw_ani_monitor(ah, ah->curchan);
799fb9987d0SSujith 
800fb9987d0SSujith 		/* Perform calibration if necessary */
801fb9987d0SSujith 		if (longcal || shortcal) {
802fb9987d0SSujith 			common->ani.caldone =
803fb9987d0SSujith 				ath9k_hw_calibrate(ah, ah->curchan,
804fb9987d0SSujith 						   common->rx_chainmask,
805fb9987d0SSujith 						   longcal);
806fb9987d0SSujith 
807fb9987d0SSujith 			if (longcal)
808fb9987d0SSujith 				common->ani.noise_floor =
809fb9987d0SSujith 					ath9k_hw_getchan_noise(ah, ah->curchan);
810fb9987d0SSujith 
811fb9987d0SSujith 			ath_print(common, ATH_DBG_ANI,
812fb9987d0SSujith 				  " calibrate chan %u/%x nf: %d\n",
813fb9987d0SSujith 				  ah->curchan->channel,
814fb9987d0SSujith 				  ah->curchan->channelFlags,
815fb9987d0SSujith 				  common->ani.noise_floor);
816fb9987d0SSujith 		}
817bde748a4SVivek Natarajan 
818bde748a4SVivek Natarajan 		ath9k_htc_ps_restore(priv);
819fb9987d0SSujith 	}
820fb9987d0SSujith 
821bde748a4SVivek Natarajan set_timer:
822fb9987d0SSujith 	/*
823fb9987d0SSujith 	* Set timer interval based on previous results.
824fb9987d0SSujith 	* The interval must be the shortest necessary to satisfy ANI,
825fb9987d0SSujith 	* short calibration and long calibration.
826fb9987d0SSujith 	*/
827fb9987d0SSujith 	cal_interval = ATH_LONG_CALINTERVAL;
828fb9987d0SSujith 	if (priv->ah->config.enable_ani)
829fb9987d0SSujith 		cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
830fb9987d0SSujith 	if (!common->ani.caldone)
831fb9987d0SSujith 		cal_interval = min(cal_interval, (u32)short_cal_interval);
832fb9987d0SSujith 
833fb9987d0SSujith 	ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
834fb9987d0SSujith 				     msecs_to_jiffies(cal_interval));
835fb9987d0SSujith }
836fb9987d0SSujith 
837fb9987d0SSujith /*******/
838fb9987d0SSujith /* LED */
839fb9987d0SSujith /*******/
840fb9987d0SSujith 
841fb9987d0SSujith static void ath9k_led_blink_work(struct work_struct *work)
842fb9987d0SSujith {
843fb9987d0SSujith 	struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
844fb9987d0SSujith 						   ath9k_led_blink_work.work);
845fb9987d0SSujith 
846fb9987d0SSujith 	if (!(priv->op_flags & OP_LED_ASSOCIATED))
847fb9987d0SSujith 		return;
848fb9987d0SSujith 
849fb9987d0SSujith 	if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
850fb9987d0SSujith 	    (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
851fb9987d0SSujith 		ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
852fb9987d0SSujith 	else
853fb9987d0SSujith 		ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
854fb9987d0SSujith 				  (priv->op_flags & OP_LED_ON) ? 1 : 0);
855fb9987d0SSujith 
856fb9987d0SSujith 	ieee80211_queue_delayed_work(priv->hw,
857fb9987d0SSujith 				     &priv->ath9k_led_blink_work,
858fb9987d0SSujith 				     (priv->op_flags & OP_LED_ON) ?
859fb9987d0SSujith 				     msecs_to_jiffies(priv->led_off_duration) :
860fb9987d0SSujith 				     msecs_to_jiffies(priv->led_on_duration));
861fb9987d0SSujith 
862fb9987d0SSujith 	priv->led_on_duration = priv->led_on_cnt ?
863fb9987d0SSujith 		max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
864fb9987d0SSujith 		ATH_LED_ON_DURATION_IDLE;
865fb9987d0SSujith 	priv->led_off_duration = priv->led_off_cnt ?
866fb9987d0SSujith 		max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
867fb9987d0SSujith 		ATH_LED_OFF_DURATION_IDLE;
868fb9987d0SSujith 	priv->led_on_cnt = priv->led_off_cnt = 0;
869fb9987d0SSujith 
870fb9987d0SSujith 	if (priv->op_flags & OP_LED_ON)
871fb9987d0SSujith 		priv->op_flags &= ~OP_LED_ON;
872fb9987d0SSujith 	else
873fb9987d0SSujith 		priv->op_flags |= OP_LED_ON;
874fb9987d0SSujith }
875fb9987d0SSujith 
876fb9987d0SSujith static void ath9k_led_brightness_work(struct work_struct *work)
877fb9987d0SSujith {
878fb9987d0SSujith 	struct ath_led *led = container_of(work, struct ath_led,
879fb9987d0SSujith 					   brightness_work.work);
880fb9987d0SSujith 	struct ath9k_htc_priv *priv = led->priv;
881fb9987d0SSujith 
882fb9987d0SSujith 	switch (led->brightness) {
883fb9987d0SSujith 	case LED_OFF:
884fb9987d0SSujith 		if (led->led_type == ATH_LED_ASSOC ||
885fb9987d0SSujith 		    led->led_type == ATH_LED_RADIO) {
886fb9987d0SSujith 			ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
887fb9987d0SSujith 					  (led->led_type == ATH_LED_RADIO));
888fb9987d0SSujith 			priv->op_flags &= ~OP_LED_ASSOCIATED;
889fb9987d0SSujith 			if (led->led_type == ATH_LED_RADIO)
890fb9987d0SSujith 				priv->op_flags &= ~OP_LED_ON;
891fb9987d0SSujith 		} else {
892fb9987d0SSujith 			priv->led_off_cnt++;
893fb9987d0SSujith 		}
894fb9987d0SSujith 		break;
895fb9987d0SSujith 	case LED_FULL:
896fb9987d0SSujith 		if (led->led_type == ATH_LED_ASSOC) {
897fb9987d0SSujith 			priv->op_flags |= OP_LED_ASSOCIATED;
898fb9987d0SSujith 			ieee80211_queue_delayed_work(priv->hw,
899fb9987d0SSujith 					     &priv->ath9k_led_blink_work, 0);
900fb9987d0SSujith 		} else if (led->led_type == ATH_LED_RADIO) {
901fb9987d0SSujith 			ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
902fb9987d0SSujith 			priv->op_flags |= OP_LED_ON;
903fb9987d0SSujith 		} else {
904fb9987d0SSujith 			priv->led_on_cnt++;
905fb9987d0SSujith 		}
906fb9987d0SSujith 		break;
907fb9987d0SSujith 	default:
908fb9987d0SSujith 		break;
909fb9987d0SSujith 	}
910fb9987d0SSujith }
911fb9987d0SSujith 
912fb9987d0SSujith static void ath9k_led_brightness(struct led_classdev *led_cdev,
913fb9987d0SSujith 				 enum led_brightness brightness)
914fb9987d0SSujith {
915fb9987d0SSujith 	struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
916fb9987d0SSujith 	struct ath9k_htc_priv *priv = led->priv;
917fb9987d0SSujith 
918fb9987d0SSujith 	led->brightness = brightness;
919fb9987d0SSujith 	if (!(priv->op_flags & OP_LED_DEINIT))
920fb9987d0SSujith 		ieee80211_queue_delayed_work(priv->hw,
921fb9987d0SSujith 					     &led->brightness_work, 0);
922fb9987d0SSujith }
923fb9987d0SSujith 
924fb9987d0SSujith static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
925fb9987d0SSujith {
926fb9987d0SSujith 	cancel_delayed_work_sync(&priv->radio_led.brightness_work);
927fb9987d0SSujith 	cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
928fb9987d0SSujith 	cancel_delayed_work_sync(&priv->tx_led.brightness_work);
929fb9987d0SSujith 	cancel_delayed_work_sync(&priv->rx_led.brightness_work);
930fb9987d0SSujith }
931fb9987d0SSujith 
932fb9987d0SSujith static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
933fb9987d0SSujith 			      char *trigger)
934fb9987d0SSujith {
935fb9987d0SSujith 	int ret;
936fb9987d0SSujith 
937fb9987d0SSujith 	led->priv = priv;
938fb9987d0SSujith 	led->led_cdev.name = led->name;
939fb9987d0SSujith 	led->led_cdev.default_trigger = trigger;
940fb9987d0SSujith 	led->led_cdev.brightness_set = ath9k_led_brightness;
941fb9987d0SSujith 
942fb9987d0SSujith 	ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
943fb9987d0SSujith 	if (ret)
944fb9987d0SSujith 		ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
945fb9987d0SSujith 			  "Failed to register led:%s", led->name);
946fb9987d0SSujith 	else
947fb9987d0SSujith 		led->registered = 1;
948fb9987d0SSujith 
949fb9987d0SSujith 	INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
950fb9987d0SSujith 
951fb9987d0SSujith 	return ret;
952fb9987d0SSujith }
953fb9987d0SSujith 
954fb9987d0SSujith static void ath9k_unregister_led(struct ath_led *led)
955fb9987d0SSujith {
956fb9987d0SSujith 	if (led->registered) {
957fb9987d0SSujith 		led_classdev_unregister(&led->led_cdev);
958fb9987d0SSujith 		led->registered = 0;
959fb9987d0SSujith 	}
960fb9987d0SSujith }
961fb9987d0SSujith 
962fb9987d0SSujith void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
963fb9987d0SSujith {
964fb9987d0SSujith 	priv->op_flags |= OP_LED_DEINIT;
965fb9987d0SSujith 	ath9k_unregister_led(&priv->assoc_led);
966fb9987d0SSujith 	priv->op_flags &= ~OP_LED_ASSOCIATED;
967fb9987d0SSujith 	ath9k_unregister_led(&priv->tx_led);
968fb9987d0SSujith 	ath9k_unregister_led(&priv->rx_led);
969fb9987d0SSujith 	ath9k_unregister_led(&priv->radio_led);
970fb9987d0SSujith }
971fb9987d0SSujith 
972fb9987d0SSujith void ath9k_init_leds(struct ath9k_htc_priv *priv)
973fb9987d0SSujith {
974fb9987d0SSujith 	char *trigger;
975fb9987d0SSujith 	int ret;
976fb9987d0SSujith 
977fb9987d0SSujith 	if (AR_SREV_9287(priv->ah))
978fb9987d0SSujith 		priv->ah->led_pin = ATH_LED_PIN_9287;
979fb9987d0SSujith 	else if (AR_SREV_9271(priv->ah))
980fb9987d0SSujith 		priv->ah->led_pin = ATH_LED_PIN_9271;
981fb9987d0SSujith 	else
982fb9987d0SSujith 		priv->ah->led_pin = ATH_LED_PIN_DEF;
983fb9987d0SSujith 
984fb9987d0SSujith 	/* Configure gpio 1 for output */
985fb9987d0SSujith 	ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
986fb9987d0SSujith 			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
987fb9987d0SSujith 	/* LED off, active low */
988fb9987d0SSujith 	ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
989fb9987d0SSujith 
990fb9987d0SSujith 	INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
991fb9987d0SSujith 
992fb9987d0SSujith 	trigger = ieee80211_get_radio_led_name(priv->hw);
993fb9987d0SSujith 	snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
994fb9987d0SSujith 		"ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
995fb9987d0SSujith 	ret = ath9k_register_led(priv, &priv->radio_led, trigger);
996fb9987d0SSujith 	priv->radio_led.led_type = ATH_LED_RADIO;
997fb9987d0SSujith 	if (ret)
998fb9987d0SSujith 		goto fail;
999fb9987d0SSujith 
1000fb9987d0SSujith 	trigger = ieee80211_get_assoc_led_name(priv->hw);
1001fb9987d0SSujith 	snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
1002fb9987d0SSujith 		"ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
1003fb9987d0SSujith 	ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
1004fb9987d0SSujith 	priv->assoc_led.led_type = ATH_LED_ASSOC;
1005fb9987d0SSujith 	if (ret)
1006fb9987d0SSujith 		goto fail;
1007fb9987d0SSujith 
1008fb9987d0SSujith 	trigger = ieee80211_get_tx_led_name(priv->hw);
1009fb9987d0SSujith 	snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
1010fb9987d0SSujith 		"ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
1011fb9987d0SSujith 	ret = ath9k_register_led(priv, &priv->tx_led, trigger);
1012fb9987d0SSujith 	priv->tx_led.led_type = ATH_LED_TX;
1013fb9987d0SSujith 	if (ret)
1014fb9987d0SSujith 		goto fail;
1015fb9987d0SSujith 
1016fb9987d0SSujith 	trigger = ieee80211_get_rx_led_name(priv->hw);
1017fb9987d0SSujith 	snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
1018fb9987d0SSujith 		"ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
1019fb9987d0SSujith 	ret = ath9k_register_led(priv, &priv->rx_led, trigger);
1020fb9987d0SSujith 	priv->rx_led.led_type = ATH_LED_RX;
1021fb9987d0SSujith 	if (ret)
1022fb9987d0SSujith 		goto fail;
1023fb9987d0SSujith 
1024fb9987d0SSujith 	priv->op_flags &= ~OP_LED_DEINIT;
1025fb9987d0SSujith 
1026fb9987d0SSujith 	return;
1027fb9987d0SSujith 
1028fb9987d0SSujith fail:
1029fb9987d0SSujith 	cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
1030fb9987d0SSujith 	ath9k_deinit_leds(priv);
1031fb9987d0SSujith }
1032fb9987d0SSujith 
1033fb9987d0SSujith /*******************/
1034fb9987d0SSujith /*	Rfkill	   */
1035fb9987d0SSujith /*******************/
1036fb9987d0SSujith 
1037fb9987d0SSujith static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
1038fb9987d0SSujith {
1039fb9987d0SSujith 	return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
1040fb9987d0SSujith 		priv->ah->rfkill_polarity;
1041fb9987d0SSujith }
1042fb9987d0SSujith 
1043fb9987d0SSujith static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
1044fb9987d0SSujith {
1045fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1046fb9987d0SSujith 	bool blocked = !!ath_is_rfkill_set(priv);
1047fb9987d0SSujith 
1048fb9987d0SSujith 	wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
1049fb9987d0SSujith }
1050fb9987d0SSujith 
1051fb9987d0SSujith void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
1052fb9987d0SSujith {
1053fb9987d0SSujith 	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
1054fb9987d0SSujith 		wiphy_rfkill_start_polling(priv->hw->wiphy);
1055fb9987d0SSujith }
1056fb9987d0SSujith 
1057fb9987d0SSujith /**********************/
1058fb9987d0SSujith /* mac80211 Callbacks */
1059fb9987d0SSujith /**********************/
1060fb9987d0SSujith 
1061fb9987d0SSujith static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
1062fb9987d0SSujith {
1063fb9987d0SSujith 	struct ieee80211_hdr *hdr;
1064fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
10657757dfedSSujith 	int padpos, padsize, ret;
1066fb9987d0SSujith 
1067fb9987d0SSujith 	hdr = (struct ieee80211_hdr *) skb->data;
1068fb9987d0SSujith 
1069fb9987d0SSujith 	/* Add the padding after the header if this is not already done */
1070fb9987d0SSujith 	padpos = ath9k_cmn_padpos(hdr->frame_control);
1071fb9987d0SSujith 	padsize = padpos & 3;
1072fb9987d0SSujith 	if (padsize && skb->len > padpos) {
1073fb9987d0SSujith 		if (skb_headroom(skb) < padsize)
1074fb9987d0SSujith 			return -1;
1075fb9987d0SSujith 		skb_push(skb, padsize);
1076fb9987d0SSujith 		memmove(skb->data, skb->data + padsize, padpos);
1077fb9987d0SSujith 	}
1078fb9987d0SSujith 
10797757dfedSSujith 	ret = ath9k_htc_tx_start(priv, skb);
10807757dfedSSujith 	if (ret != 0) {
10817757dfedSSujith 		if (ret == -ENOMEM) {
10827757dfedSSujith 			ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
10837757dfedSSujith 				  "Stopping TX queues\n");
10847757dfedSSujith 			ieee80211_stop_queues(hw);
10857757dfedSSujith 			spin_lock_bh(&priv->tx_lock);
10867757dfedSSujith 			priv->tx_queues_stop = true;
10877757dfedSSujith 			spin_unlock_bh(&priv->tx_lock);
10887757dfedSSujith 		} else {
10897757dfedSSujith 			ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
10907757dfedSSujith 				  "Tx failed");
10917757dfedSSujith 		}
1092fb9987d0SSujith 		goto fail_tx;
1093fb9987d0SSujith 	}
1094fb9987d0SSujith 
1095fb9987d0SSujith 	return 0;
1096fb9987d0SSujith 
1097fb9987d0SSujith fail_tx:
1098fb9987d0SSujith 	dev_kfree_skb_any(skb);
1099fb9987d0SSujith 	return 0;
1100fb9987d0SSujith }
1101fb9987d0SSujith 
11022ff6575bSSujith static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led)
1103fb9987d0SSujith {
1104fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1105fb9987d0SSujith 	struct ath_hw *ah = priv->ah;
1106fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(ah);
1107fb9987d0SSujith 	struct ieee80211_channel *curchan = hw->conf.channel;
1108fb9987d0SSujith 	struct ath9k_channel *init_channel;
1109fb9987d0SSujith 	int ret = 0;
1110fb9987d0SSujith 	enum htc_phymode mode;
11117f1f5a00SSujith 	__be16 htc_mode;
1112fb9987d0SSujith 	u8 cmd_rsp;
1113fb9987d0SSujith 
1114fb9987d0SSujith 	ath_print(common, ATH_DBG_CONFIG,
1115fb9987d0SSujith 		  "Starting driver with initial channel: %d MHz\n",
1116fb9987d0SSujith 		  curchan->center_freq);
1117fb9987d0SSujith 
1118fb9987d0SSujith 	/* setup initial channel */
1119fb9987d0SSujith 	init_channel = ath9k_cmn_get_curchannel(hw, ah);
1120fb9987d0SSujith 
1121fb9987d0SSujith 	/* Reset SERDES registers */
1122fb9987d0SSujith 	ath9k_hw_configpcipowersave(ah, 0, 0);
1123fb9987d0SSujith 
1124fb9987d0SSujith 	ath9k_hw_htc_resetinit(ah);
1125fb9987d0SSujith 	ret = ath9k_hw_reset(ah, init_channel, false);
1126fb9987d0SSujith 	if (ret) {
1127fb9987d0SSujith 		ath_print(common, ATH_DBG_FATAL,
1128fb9987d0SSujith 			  "Unable to reset hardware; reset status %d "
1129fb9987d0SSujith 			  "(freq %u MHz)\n", ret, curchan->center_freq);
11308a8572a8SVivek Natarajan 		return ret;
1131fb9987d0SSujith 	}
1132fb9987d0SSujith 
1133fb9987d0SSujith 	ath_update_txpow(priv);
1134fb9987d0SSujith 
1135fb9987d0SSujith 	mode = ath9k_htc_get_curmode(priv, init_channel);
1136fb9987d0SSujith 	htc_mode = cpu_to_be16(mode);
1137fb9987d0SSujith 	WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
1138fb9987d0SSujith 	WMI_CMD(WMI_ATH_INIT_CMDID);
1139fb9987d0SSujith 	WMI_CMD(WMI_START_RECV_CMDID);
1140fb9987d0SSujith 
1141fb9987d0SSujith 	ath9k_host_rx_init(priv);
1142fb9987d0SSujith 
1143fb9987d0SSujith 	priv->op_flags &= ~OP_INVALID;
1144fb9987d0SSujith 	htc_start(priv->htc);
1145fb9987d0SSujith 
11467757dfedSSujith 	spin_lock_bh(&priv->tx_lock);
11477757dfedSSujith 	priv->tx_queues_stop = false;
11487757dfedSSujith 	spin_unlock_bh(&priv->tx_lock);
11497757dfedSSujith 
11502ff6575bSSujith 	if (led) {
11512ff6575bSSujith 		/* Enable LED */
11522ff6575bSSujith 		ath9k_hw_cfg_output(ah, ah->led_pin,
11532ff6575bSSujith 				    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
11542ff6575bSSujith 		ath9k_hw_set_gpio(ah, ah->led_pin, 0);
11552ff6575bSSujith 	}
11562ff6575bSSujith 
11577757dfedSSujith 	ieee80211_wake_queues(hw);
11587757dfedSSujith 
1159fb9987d0SSujith 	return ret;
1160fb9987d0SSujith }
1161fb9987d0SSujith 
11628a8572a8SVivek Natarajan static int ath9k_htc_start(struct ieee80211_hw *hw)
11638a8572a8SVivek Natarajan {
11648a8572a8SVivek Natarajan 	struct ath9k_htc_priv *priv = hw->priv;
11658a8572a8SVivek Natarajan 	int ret = 0;
11668a8572a8SVivek Natarajan 
11678a8572a8SVivek Natarajan 	mutex_lock(&priv->mutex);
11682ff6575bSSujith 	ret = ath9k_htc_radio_enable(hw, false);
11698a8572a8SVivek Natarajan 	mutex_unlock(&priv->mutex);
11708a8572a8SVivek Natarajan 
11718a8572a8SVivek Natarajan 	return ret;
11728a8572a8SVivek Natarajan }
11738a8572a8SVivek Natarajan 
11742ff6575bSSujith static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led)
1175fb9987d0SSujith {
1176fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1177fb9987d0SSujith 	struct ath_hw *ah = priv->ah;
1178fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(ah);
1179fb9987d0SSujith 	int ret = 0;
1180fb9987d0SSujith 	u8 cmd_rsp;
1181fb9987d0SSujith 
1182fb9987d0SSujith 	if (priv->op_flags & OP_INVALID) {
1183fb9987d0SSujith 		ath_print(common, ATH_DBG_ANY, "Device not present\n");
1184fb9987d0SSujith 		return;
1185fb9987d0SSujith 	}
1186fb9987d0SSujith 
11872ff6575bSSujith 	if (led) {
11882ff6575bSSujith 		/* Disable LED */
11892ff6575bSSujith 		ath9k_hw_set_gpio(ah, ah->led_pin, 1);
11902ff6575bSSujith 		ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
11912ff6575bSSujith 	}
11922ff6575bSSujith 
11937073daa6SSujith 	/* Cancel all the running timers/work .. */
11947073daa6SSujith 	cancel_work_sync(&priv->ps_work);
11957073daa6SSujith 	cancel_delayed_work_sync(&priv->ath9k_ani_work);
11967073daa6SSujith 	cancel_delayed_work_sync(&priv->ath9k_aggr_work);
11977073daa6SSujith 	cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
11987073daa6SSujith 	ath9k_led_stop_brightness(priv);
11997073daa6SSujith 
1200bde748a4SVivek Natarajan 	ath9k_htc_ps_wakeup(priv);
1201fb9987d0SSujith 	htc_stop(priv->htc);
1202fb9987d0SSujith 	WMI_CMD(WMI_DISABLE_INTR_CMDID);
1203fb9987d0SSujith 	WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
1204fb9987d0SSujith 	WMI_CMD(WMI_STOP_RECV_CMDID);
1205fb9987d0SSujith 	ath9k_hw_phy_disable(ah);
1206fb9987d0SSujith 	ath9k_hw_disable(ah);
1207fb9987d0SSujith 	ath9k_hw_configpcipowersave(ah, 1, 1);
1208bde748a4SVivek Natarajan 	ath9k_htc_ps_restore(priv);
1209bde748a4SVivek Natarajan 	ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
1210fb9987d0SSujith 
1211fb9987d0SSujith 	skb_queue_purge(&priv->tx_queue);
1212fb9987d0SSujith 
1213fb9987d0SSujith 	/* Remove monitor interface here */
1214fb9987d0SSujith 	if (ah->opmode == NL80211_IFTYPE_MONITOR) {
1215fb9987d0SSujith 		if (ath9k_htc_remove_monitor_interface(priv))
1216fb9987d0SSujith 			ath_print(common, ATH_DBG_FATAL,
1217fb9987d0SSujith 				  "Unable to remove monitor interface\n");
1218fb9987d0SSujith 		else
1219fb9987d0SSujith 			ath_print(common, ATH_DBG_CONFIG,
1220fb9987d0SSujith 				  "Monitor interface removed\n");
1221fb9987d0SSujith 	}
1222fb9987d0SSujith 
1223fb9987d0SSujith 	priv->op_flags |= OP_INVALID;
1224fb9987d0SSujith 
1225fb9987d0SSujith 	ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
1226fb9987d0SSujith }
1227fb9987d0SSujith 
12288a8572a8SVivek Natarajan static void ath9k_htc_stop(struct ieee80211_hw *hw)
12298a8572a8SVivek Natarajan {
12308a8572a8SVivek Natarajan 	struct ath9k_htc_priv *priv = hw->priv;
12318a8572a8SVivek Natarajan 
12328a8572a8SVivek Natarajan 	mutex_lock(&priv->mutex);
12332ff6575bSSujith 	ath9k_htc_radio_disable(hw, false);
12348a8572a8SVivek Natarajan 	mutex_unlock(&priv->mutex);
12358a8572a8SVivek Natarajan }
12368a8572a8SVivek Natarajan 
12378a8572a8SVivek Natarajan 
1238fb9987d0SSujith static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
1239fb9987d0SSujith 				   struct ieee80211_vif *vif)
1240fb9987d0SSujith {
1241fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1242fb9987d0SSujith 	struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1243fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
1244fb9987d0SSujith 	struct ath9k_htc_target_vif hvif;
1245fb9987d0SSujith 	int ret = 0;
1246fb9987d0SSujith 	u8 cmd_rsp;
1247fb9987d0SSujith 
1248fb9987d0SSujith 	mutex_lock(&priv->mutex);
1249fb9987d0SSujith 
1250fb9987d0SSujith 	/* Only one interface for now */
1251fb9987d0SSujith 	if (priv->nvifs > 0) {
1252fb9987d0SSujith 		ret = -ENOBUFS;
1253fb9987d0SSujith 		goto out;
1254fb9987d0SSujith 	}
1255fb9987d0SSujith 
1256bde748a4SVivek Natarajan 	ath9k_htc_ps_wakeup(priv);
1257fb9987d0SSujith 	memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1258fb9987d0SSujith 	memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1259fb9987d0SSujith 
1260fb9987d0SSujith 	switch (vif->type) {
1261fb9987d0SSujith 	case NL80211_IFTYPE_STATION:
1262fb9987d0SSujith 		hvif.opmode = cpu_to_be32(HTC_M_STA);
1263fb9987d0SSujith 		break;
1264fb9987d0SSujith 	case NL80211_IFTYPE_ADHOC:
1265fb9987d0SSujith 		hvif.opmode = cpu_to_be32(HTC_M_IBSS);
1266fb9987d0SSujith 		break;
1267fb9987d0SSujith 	default:
1268fb9987d0SSujith 		ath_print(common, ATH_DBG_FATAL,
1269fb9987d0SSujith 			"Interface type %d not yet supported\n", vif->type);
1270fb9987d0SSujith 		ret = -EOPNOTSUPP;
1271fb9987d0SSujith 		goto out;
1272fb9987d0SSujith 	}
1273fb9987d0SSujith 
1274fb9987d0SSujith 	ath_print(common, ATH_DBG_CONFIG,
1275fb9987d0SSujith 		  "Attach a VIF of type: %d\n", vif->type);
1276fb9987d0SSujith 
1277fb9987d0SSujith 	priv->ah->opmode = vif->type;
1278fb9987d0SSujith 
1279fb9987d0SSujith 	/* Index starts from zero on the target */
1280fb9987d0SSujith 	avp->index = hvif.index = priv->nvifs;
1281fb9987d0SSujith 	hvif.rtsthreshold = cpu_to_be16(2304);
1282fb9987d0SSujith 	WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
1283fb9987d0SSujith 	if (ret)
1284fb9987d0SSujith 		goto out;
1285fb9987d0SSujith 
1286fb9987d0SSujith 	priv->nvifs++;
1287fb9987d0SSujith 
1288fb9987d0SSujith 	/*
1289fb9987d0SSujith 	 * We need a node in target to tx mgmt frames
1290fb9987d0SSujith 	 * before association.
1291fb9987d0SSujith 	 */
1292fb9987d0SSujith 	ret = ath9k_htc_add_station(priv, vif, NULL);
1293fb9987d0SSujith 	if (ret)
1294fb9987d0SSujith 		goto out;
1295fb9987d0SSujith 
1296fb9987d0SSujith 	ret = ath9k_htc_update_cap_target(priv);
1297fb9987d0SSujith 	if (ret)
1298fb9987d0SSujith 		ath_print(common, ATH_DBG_CONFIG, "Failed to update"
1299fb9987d0SSujith 			  " capability in target \n");
1300fb9987d0SSujith 
1301fb9987d0SSujith 	priv->vif = vif;
1302fb9987d0SSujith out:
1303bde748a4SVivek Natarajan 	ath9k_htc_ps_restore(priv);
1304fb9987d0SSujith 	mutex_unlock(&priv->mutex);
1305fb9987d0SSujith 	return ret;
1306fb9987d0SSujith }
1307fb9987d0SSujith 
1308fb9987d0SSujith static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
1309fb9987d0SSujith 				       struct ieee80211_vif *vif)
1310fb9987d0SSujith {
1311fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1312fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
1313fb9987d0SSujith 	struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
1314fb9987d0SSujith 	struct ath9k_htc_target_vif hvif;
1315fb9987d0SSujith 	int ret = 0;
1316fb9987d0SSujith 	u8 cmd_rsp;
1317fb9987d0SSujith 
1318fb9987d0SSujith 	ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
1319fb9987d0SSujith 
1320fb9987d0SSujith 	mutex_lock(&priv->mutex);
1321fb9987d0SSujith 
1322fb9987d0SSujith 	memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
1323fb9987d0SSujith 	memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
1324fb9987d0SSujith 	hvif.index = avp->index;
1325fb9987d0SSujith 	WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
1326fb9987d0SSujith 	priv->nvifs--;
1327fb9987d0SSujith 
1328fb9987d0SSujith 	ath9k_htc_remove_station(priv, vif, NULL);
1329fb9987d0SSujith 	priv->vif = NULL;
1330fb9987d0SSujith 
1331fb9987d0SSujith 	mutex_unlock(&priv->mutex);
1332fb9987d0SSujith }
1333fb9987d0SSujith 
1334fb9987d0SSujith static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
1335fb9987d0SSujith {
1336fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1337fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
1338fb9987d0SSujith 	struct ieee80211_conf *conf = &hw->conf;
1339fb9987d0SSujith 
1340fb9987d0SSujith 	mutex_lock(&priv->mutex);
1341fb9987d0SSujith 
13428a8572a8SVivek Natarajan 	if (changed & IEEE80211_CONF_CHANGE_IDLE) {
13438a8572a8SVivek Natarajan 		bool enable_radio = false;
13448a8572a8SVivek Natarajan 		bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
13458a8572a8SVivek Natarajan 
13468a8572a8SVivek Natarajan 		if (!idle && priv->ps_idle)
13478a8572a8SVivek Natarajan 			enable_radio = true;
13488a8572a8SVivek Natarajan 
13498a8572a8SVivek Natarajan 		priv->ps_idle = idle;
13508a8572a8SVivek Natarajan 
13518a8572a8SVivek Natarajan 		if (enable_radio) {
13528a8572a8SVivek Natarajan 			ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
13532ff6575bSSujith 			ath9k_htc_radio_enable(hw, true);
13548a8572a8SVivek Natarajan 			ath_print(common, ATH_DBG_CONFIG,
13558a8572a8SVivek Natarajan 				  "not-idle: enabling radio\n");
13568a8572a8SVivek Natarajan 		}
13578a8572a8SVivek Natarajan 	}
13588a8572a8SVivek Natarajan 
1359fb9987d0SSujith 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1360fb9987d0SSujith 		struct ieee80211_channel *curchan = hw->conf.channel;
1361fb9987d0SSujith 		int pos = curchan->hw_value;
1362fb9987d0SSujith 		bool is_cw40 = false;
1363fb9987d0SSujith 
1364fb9987d0SSujith 		ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
1365fb9987d0SSujith 			  curchan->center_freq);
1366fb9987d0SSujith 
1367fb9987d0SSujith 		if (check_rc_update(hw, &is_cw40))
1368fb9987d0SSujith 			ath9k_htc_rc_update(priv, is_cw40);
1369fb9987d0SSujith 
1370fb9987d0SSujith 		ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
1371fb9987d0SSujith 
1372fb9987d0SSujith 		if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
1373fb9987d0SSujith 			ath_print(common, ATH_DBG_FATAL,
1374fb9987d0SSujith 				  "Unable to set channel\n");
1375fb9987d0SSujith 			mutex_unlock(&priv->mutex);
1376fb9987d0SSujith 			return -EINVAL;
1377fb9987d0SSujith 		}
1378fb9987d0SSujith 
1379fb9987d0SSujith 	}
1380bde748a4SVivek Natarajan 	if (changed & IEEE80211_CONF_CHANGE_PS) {
1381bde748a4SVivek Natarajan 		if (conf->flags & IEEE80211_CONF_PS) {
1382bde748a4SVivek Natarajan 			ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
1383bde748a4SVivek Natarajan 			priv->ps_enabled = true;
1384bde748a4SVivek Natarajan 		} else {
1385bde748a4SVivek Natarajan 			priv->ps_enabled = false;
1386bde748a4SVivek Natarajan 			cancel_work_sync(&priv->ps_work);
1387bde748a4SVivek Natarajan 			ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
1388bde748a4SVivek Natarajan 		}
1389bde748a4SVivek Natarajan 	}
1390fb9987d0SSujith 
1391fb9987d0SSujith 	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
1392fb9987d0SSujith 		if (conf->flags & IEEE80211_CONF_MONITOR) {
1393fb9987d0SSujith 			if (ath9k_htc_add_monitor_interface(priv))
1394fb9987d0SSujith 				ath_print(common, ATH_DBG_FATAL,
1395fb9987d0SSujith 					  "Failed to set monitor mode\n");
1396fb9987d0SSujith 			else
1397fb9987d0SSujith 				ath_print(common, ATH_DBG_CONFIG,
1398fb9987d0SSujith 					  "HW opmode set to Monitor mode\n");
1399fb9987d0SSujith 		}
1400fb9987d0SSujith 	}
1401fb9987d0SSujith 
14028a8572a8SVivek Natarajan 	if (priv->ps_idle) {
14038a8572a8SVivek Natarajan 		ath_print(common, ATH_DBG_CONFIG,
14048a8572a8SVivek Natarajan 			  "idle: disabling radio\n");
14052ff6575bSSujith 		ath9k_htc_radio_disable(hw, true);
14068a8572a8SVivek Natarajan 	}
14078a8572a8SVivek Natarajan 
1408fb9987d0SSujith 	mutex_unlock(&priv->mutex);
1409fb9987d0SSujith 
1410fb9987d0SSujith 	return 0;
1411fb9987d0SSujith }
1412fb9987d0SSujith 
1413fb9987d0SSujith #define SUPPORTED_FILTERS			\
1414fb9987d0SSujith 	(FIF_PROMISC_IN_BSS |			\
1415fb9987d0SSujith 	FIF_ALLMULTI |				\
1416fb9987d0SSujith 	FIF_CONTROL |				\
1417fb9987d0SSujith 	FIF_PSPOLL |				\
1418fb9987d0SSujith 	FIF_OTHER_BSS |				\
1419fb9987d0SSujith 	FIF_BCN_PRBRESP_PROMISC |		\
1420fb9987d0SSujith 	FIF_FCSFAIL)
1421fb9987d0SSujith 
1422fb9987d0SSujith static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
1423fb9987d0SSujith 				       unsigned int changed_flags,
1424fb9987d0SSujith 				       unsigned int *total_flags,
1425fb9987d0SSujith 				       u64 multicast)
1426fb9987d0SSujith {
1427fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1428fb9987d0SSujith 	u32 rfilt;
1429fb9987d0SSujith 
1430fb9987d0SSujith 	mutex_lock(&priv->mutex);
1431fb9987d0SSujith 
1432bde748a4SVivek Natarajan 	ath9k_htc_ps_wakeup(priv);
1433fb9987d0SSujith 	changed_flags &= SUPPORTED_FILTERS;
1434fb9987d0SSujith 	*total_flags &= SUPPORTED_FILTERS;
1435fb9987d0SSujith 
1436fb9987d0SSujith 	priv->rxfilter = *total_flags;
14370995d110SSujith 	rfilt = ath9k_htc_calcrxfilter(priv);
1438fb9987d0SSujith 	ath9k_hw_setrxfilter(priv->ah, rfilt);
1439fb9987d0SSujith 
1440fb9987d0SSujith 	ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
1441fb9987d0SSujith 		  "Set HW RX filter: 0x%x\n", rfilt);
1442fb9987d0SSujith 
1443bde748a4SVivek Natarajan 	ath9k_htc_ps_restore(priv);
1444fb9987d0SSujith 	mutex_unlock(&priv->mutex);
1445fb9987d0SSujith }
1446fb9987d0SSujith 
1447fb9987d0SSujith static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
1448fb9987d0SSujith 				 struct ieee80211_vif *vif,
1449fb9987d0SSujith 				 enum sta_notify_cmd cmd,
1450fb9987d0SSujith 				 struct ieee80211_sta *sta)
1451fb9987d0SSujith {
1452fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1453fb9987d0SSujith 	int ret;
1454fb9987d0SSujith 
1455fb9987d0SSujith 	switch (cmd) {
1456fb9987d0SSujith 	case STA_NOTIFY_ADD:
1457fb9987d0SSujith 		ret = ath9k_htc_add_station(priv, vif, sta);
1458fb9987d0SSujith 		if (!ret)
1459fb9987d0SSujith 			ath9k_htc_init_rate(priv, vif, sta);
1460fb9987d0SSujith 		break;
1461fb9987d0SSujith 	case STA_NOTIFY_REMOVE:
1462fb9987d0SSujith 		ath9k_htc_remove_station(priv, vif, sta);
1463fb9987d0SSujith 		break;
1464fb9987d0SSujith 	default:
1465fb9987d0SSujith 		break;
1466fb9987d0SSujith 	}
1467fb9987d0SSujith }
1468fb9987d0SSujith 
1469fb9987d0SSujith static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
1470fb9987d0SSujith 			     const struct ieee80211_tx_queue_params *params)
1471fb9987d0SSujith {
1472fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1473fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
1474fb9987d0SSujith 	struct ath9k_tx_queue_info qi;
1475fb9987d0SSujith 	int ret = 0, qnum;
1476fb9987d0SSujith 
1477fb9987d0SSujith 	if (queue >= WME_NUM_AC)
1478fb9987d0SSujith 		return 0;
1479fb9987d0SSujith 
1480fb9987d0SSujith 	mutex_lock(&priv->mutex);
1481fb9987d0SSujith 
1482fb9987d0SSujith 	memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
1483fb9987d0SSujith 
1484fb9987d0SSujith 	qi.tqi_aifs = params->aifs;
1485fb9987d0SSujith 	qi.tqi_cwmin = params->cw_min;
1486fb9987d0SSujith 	qi.tqi_cwmax = params->cw_max;
1487fb9987d0SSujith 	qi.tqi_burstTime = params->txop;
1488fb9987d0SSujith 
1489fb9987d0SSujith 	qnum = get_hw_qnum(queue, priv->hwq_map);
1490fb9987d0SSujith 
1491fb9987d0SSujith 	ath_print(common, ATH_DBG_CONFIG,
1492fb9987d0SSujith 		  "Configure tx [queue/hwq] [%d/%d],  "
1493fb9987d0SSujith 		  "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
1494fb9987d0SSujith 		  queue, qnum, params->aifs, params->cw_min,
1495fb9987d0SSujith 		  params->cw_max, params->txop);
1496fb9987d0SSujith 
1497e1572c5eSSujith 	ret = ath_htc_txq_update(priv, qnum, &qi);
1498fb9987d0SSujith 	if (ret)
1499fb9987d0SSujith 		ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
1500fb9987d0SSujith 
1501fb9987d0SSujith 	mutex_unlock(&priv->mutex);
1502fb9987d0SSujith 
1503fb9987d0SSujith 	return ret;
1504fb9987d0SSujith }
1505fb9987d0SSujith 
1506fb9987d0SSujith static int ath9k_htc_set_key(struct ieee80211_hw *hw,
1507fb9987d0SSujith 			     enum set_key_cmd cmd,
1508fb9987d0SSujith 			     struct ieee80211_vif *vif,
1509fb9987d0SSujith 			     struct ieee80211_sta *sta,
1510fb9987d0SSujith 			     struct ieee80211_key_conf *key)
1511fb9987d0SSujith {
1512fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1513fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
1514fb9987d0SSujith 	int ret = 0;
1515fb9987d0SSujith 
1516e1572c5eSSujith 	if (htc_modparam_nohwcrypt)
1517fb9987d0SSujith 		return -ENOSPC;
1518fb9987d0SSujith 
1519fb9987d0SSujith 	mutex_lock(&priv->mutex);
1520fb9987d0SSujith 	ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
1521bde748a4SVivek Natarajan 	ath9k_htc_ps_wakeup(priv);
1522fb9987d0SSujith 
1523fb9987d0SSujith 	switch (cmd) {
1524fb9987d0SSujith 	case SET_KEY:
1525fb9987d0SSujith 		ret = ath9k_cmn_key_config(common, vif, sta, key);
1526fb9987d0SSujith 		if (ret >= 0) {
1527fb9987d0SSujith 			key->hw_key_idx = ret;
1528fb9987d0SSujith 			/* push IV and Michael MIC generation to stack */
1529fb9987d0SSujith 			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
1530fb9987d0SSujith 			if (key->alg == ALG_TKIP)
1531fb9987d0SSujith 				key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
1532fb9987d0SSujith 			if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
1533fb9987d0SSujith 				key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
1534fb9987d0SSujith 			ret = 0;
1535fb9987d0SSujith 		}
1536fb9987d0SSujith 		break;
1537fb9987d0SSujith 	case DISABLE_KEY:
1538fb9987d0SSujith 		ath9k_cmn_key_delete(common, key);
1539fb9987d0SSujith 		break;
1540fb9987d0SSujith 	default:
1541fb9987d0SSujith 		ret = -EINVAL;
1542fb9987d0SSujith 	}
1543fb9987d0SSujith 
1544bde748a4SVivek Natarajan 	ath9k_htc_ps_restore(priv);
1545fb9987d0SSujith 	mutex_unlock(&priv->mutex);
1546fb9987d0SSujith 
1547fb9987d0SSujith 	return ret;
1548fb9987d0SSujith }
1549fb9987d0SSujith 
1550fb9987d0SSujith static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
1551fb9987d0SSujith 				       struct ieee80211_vif *vif,
1552fb9987d0SSujith 				       struct ieee80211_bss_conf *bss_conf,
1553fb9987d0SSujith 				       u32 changed)
1554fb9987d0SSujith {
1555fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1556fb9987d0SSujith 	struct ath_hw *ah = priv->ah;
1557fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(ah);
1558fb9987d0SSujith 
1559fb9987d0SSujith 	mutex_lock(&priv->mutex);
1560bde748a4SVivek Natarajan 	ath9k_htc_ps_wakeup(priv);
1561fb9987d0SSujith 
1562fb9987d0SSujith 	if (changed & BSS_CHANGED_ASSOC) {
1563fb9987d0SSujith 		common->curaid = bss_conf->assoc ?
1564fb9987d0SSujith 				 bss_conf->aid : 0;
1565fb9987d0SSujith 		ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
1566fb9987d0SSujith 			bss_conf->assoc);
1567fb9987d0SSujith 
1568fb9987d0SSujith 		if (bss_conf->assoc) {
1569fb9987d0SSujith 			priv->op_flags |= OP_ASSOCIATED;
1570fb9987d0SSujith 			ath_start_ani(priv);
1571fb9987d0SSujith 		} else {
1572fb9987d0SSujith 			priv->op_flags &= ~OP_ASSOCIATED;
1573bde748a4SVivek Natarajan 			cancel_work_sync(&priv->ps_work);
1574fb9987d0SSujith 			cancel_delayed_work_sync(&priv->ath9k_ani_work);
1575fb9987d0SSujith 		}
1576fb9987d0SSujith 	}
1577fb9987d0SSujith 
1578fb9987d0SSujith 	if (changed & BSS_CHANGED_BSSID) {
1579fb9987d0SSujith 		/* Set BSSID */
1580fb9987d0SSujith 		memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
1581fb9987d0SSujith 		ath9k_hw_write_associd(ah);
1582fb9987d0SSujith 
1583fb9987d0SSujith 		ath_print(common, ATH_DBG_CONFIG,
1584fb9987d0SSujith 			  "BSSID: %pM aid: 0x%x\n",
1585fb9987d0SSujith 			  common->curbssid, common->curaid);
1586fb9987d0SSujith 	}
1587fb9987d0SSujith 
1588fb9987d0SSujith 	if ((changed & BSS_CHANGED_BEACON_INT) ||
1589fb9987d0SSujith 	    (changed & BSS_CHANGED_BEACON) ||
1590fb9987d0SSujith 	    ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1591fb9987d0SSujith 	    bss_conf->enable_beacon)) {
1592fb9987d0SSujith 		priv->op_flags |= OP_ENABLE_BEACON;
15931c3652a5SVivek Natarajan 		ath9k_htc_beacon_config(priv, vif);
1594fb9987d0SSujith 	}
1595fb9987d0SSujith 
1596fb9987d0SSujith 	if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1597fb9987d0SSujith 	    !bss_conf->enable_beacon) {
1598fb9987d0SSujith 		priv->op_flags &= ~OP_ENABLE_BEACON;
15991c3652a5SVivek Natarajan 		ath9k_htc_beacon_config(priv, vif);
1600fb9987d0SSujith 	}
1601fb9987d0SSujith 
1602fb9987d0SSujith 	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1603fb9987d0SSujith 		ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
1604fb9987d0SSujith 			  bss_conf->use_short_preamble);
1605fb9987d0SSujith 		if (bss_conf->use_short_preamble)
1606fb9987d0SSujith 			priv->op_flags |= OP_PREAMBLE_SHORT;
1607fb9987d0SSujith 		else
1608fb9987d0SSujith 			priv->op_flags &= ~OP_PREAMBLE_SHORT;
1609fb9987d0SSujith 	}
1610fb9987d0SSujith 
1611fb9987d0SSujith 	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1612fb9987d0SSujith 		ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
1613fb9987d0SSujith 			  bss_conf->use_cts_prot);
1614fb9987d0SSujith 		if (bss_conf->use_cts_prot &&
1615fb9987d0SSujith 		    hw->conf.channel->band != IEEE80211_BAND_5GHZ)
1616fb9987d0SSujith 			priv->op_flags |= OP_PROTECT_ENABLE;
1617fb9987d0SSujith 		else
1618fb9987d0SSujith 			priv->op_flags &= ~OP_PROTECT_ENABLE;
1619fb9987d0SSujith 	}
1620fb9987d0SSujith 
1621fb9987d0SSujith 	if (changed & BSS_CHANGED_ERP_SLOT) {
1622fb9987d0SSujith 		if (bss_conf->use_short_slot)
1623fb9987d0SSujith 			ah->slottime = 9;
1624fb9987d0SSujith 		else
1625fb9987d0SSujith 			ah->slottime = 20;
1626fb9987d0SSujith 
1627fb9987d0SSujith 		ath9k_hw_init_global_settings(ah);
1628fb9987d0SSujith 	}
1629fb9987d0SSujith 
1630bde748a4SVivek Natarajan 	ath9k_htc_ps_restore(priv);
1631fb9987d0SSujith 	mutex_unlock(&priv->mutex);
1632fb9987d0SSujith }
1633fb9987d0SSujith 
1634fb9987d0SSujith static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
1635fb9987d0SSujith {
1636fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1637fb9987d0SSujith 	u64 tsf;
1638fb9987d0SSujith 
1639fb9987d0SSujith 	mutex_lock(&priv->mutex);
1640fb9987d0SSujith 	tsf = ath9k_hw_gettsf64(priv->ah);
1641fb9987d0SSujith 	mutex_unlock(&priv->mutex);
1642fb9987d0SSujith 
1643fb9987d0SSujith 	return tsf;
1644fb9987d0SSujith }
1645fb9987d0SSujith 
1646fb9987d0SSujith static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
1647fb9987d0SSujith {
1648fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1649fb9987d0SSujith 
1650fb9987d0SSujith 	mutex_lock(&priv->mutex);
1651fb9987d0SSujith 	ath9k_hw_settsf64(priv->ah, tsf);
1652fb9987d0SSujith 	mutex_unlock(&priv->mutex);
1653fb9987d0SSujith }
1654fb9987d0SSujith 
1655fb9987d0SSujith static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
1656fb9987d0SSujith {
1657fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1658fb9987d0SSujith 
1659bde748a4SVivek Natarajan 	ath9k_htc_ps_wakeup(priv);
1660fb9987d0SSujith 	mutex_lock(&priv->mutex);
1661fb9987d0SSujith 	ath9k_hw_reset_tsf(priv->ah);
1662fb9987d0SSujith 	mutex_unlock(&priv->mutex);
1663bde748a4SVivek Natarajan 	ath9k_htc_ps_restore(priv);
1664fb9987d0SSujith }
1665fb9987d0SSujith 
1666fb9987d0SSujith static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
1667fb9987d0SSujith 				  struct ieee80211_vif *vif,
1668fb9987d0SSujith 				  enum ieee80211_ampdu_mlme_action action,
1669fb9987d0SSujith 				  struct ieee80211_sta *sta,
1670fb9987d0SSujith 				  u16 tid, u16 *ssn)
1671fb9987d0SSujith {
1672fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1673fb9987d0SSujith 	struct ath9k_htc_aggr_work *work = &priv->aggr_work;
1674fb9987d0SSujith 	struct ath9k_htc_sta *ista;
1675fb9987d0SSujith 
1676fb9987d0SSujith 	switch (action) {
1677fb9987d0SSujith 	case IEEE80211_AMPDU_RX_START:
1678fb9987d0SSujith 		break;
1679fb9987d0SSujith 	case IEEE80211_AMPDU_RX_STOP:
1680fb9987d0SSujith 		break;
1681fb9987d0SSujith 	case IEEE80211_AMPDU_TX_START:
1682fb9987d0SSujith 	case IEEE80211_AMPDU_TX_STOP:
1683fb9987d0SSujith 		if (!(priv->op_flags & OP_TXAGGR))
1684fb9987d0SSujith 			return -ENOTSUPP;
1685fb9987d0SSujith 		memcpy(work->sta_addr, sta->addr, ETH_ALEN);
1686fb9987d0SSujith 		work->hw = hw;
1687fb9987d0SSujith 		work->vif = vif;
1688fb9987d0SSujith 		work->action = action;
1689fb9987d0SSujith 		work->tid = tid;
1690fb9987d0SSujith 		ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0);
1691fb9987d0SSujith 		break;
1692fb9987d0SSujith 	case IEEE80211_AMPDU_TX_OPERATIONAL:
1693fb9987d0SSujith 		ista = (struct ath9k_htc_sta *) sta->drv_priv;
1694fb9987d0SSujith 		ista->tid_state[tid] = AGGR_OPERATIONAL;
1695fb9987d0SSujith 		break;
1696fb9987d0SSujith 	default:
1697fb9987d0SSujith 		ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
1698fb9987d0SSujith 			  "Unknown AMPDU action\n");
1699fb9987d0SSujith 	}
1700fb9987d0SSujith 
1701fb9987d0SSujith 	return 0;
1702fb9987d0SSujith }
1703fb9987d0SSujith 
1704fb9987d0SSujith static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
1705fb9987d0SSujith {
1706fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1707fb9987d0SSujith 
1708fb9987d0SSujith 	mutex_lock(&priv->mutex);
1709fb9987d0SSujith 	spin_lock_bh(&priv->beacon_lock);
1710fb9987d0SSujith 	priv->op_flags |= OP_SCANNING;
1711fb9987d0SSujith 	spin_unlock_bh(&priv->beacon_lock);
1712bde748a4SVivek Natarajan 	cancel_work_sync(&priv->ps_work);
1713fb9987d0SSujith 	cancel_delayed_work_sync(&priv->ath9k_ani_work);
1714fb9987d0SSujith 	mutex_unlock(&priv->mutex);
1715fb9987d0SSujith }
1716fb9987d0SSujith 
1717fb9987d0SSujith static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
1718fb9987d0SSujith {
1719fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1720fb9987d0SSujith 
1721bde748a4SVivek Natarajan 	ath9k_htc_ps_wakeup(priv);
1722fb9987d0SSujith 	mutex_lock(&priv->mutex);
1723fb9987d0SSujith 	spin_lock_bh(&priv->beacon_lock);
1724fb9987d0SSujith 	priv->op_flags &= ~OP_SCANNING;
1725fb9987d0SSujith 	spin_unlock_bh(&priv->beacon_lock);
1726fb9987d0SSujith 	priv->op_flags |= OP_FULL_RESET;
17271c3652a5SVivek Natarajan 	if (priv->op_flags & OP_ASSOCIATED)
1728fcb9392fSSujith 		ath9k_htc_beacon_config(priv, priv->vif);
1729fb9987d0SSujith 	ath_start_ani(priv);
1730fb9987d0SSujith 	mutex_unlock(&priv->mutex);
1731bde748a4SVivek Natarajan 	ath9k_htc_ps_restore(priv);
1732fb9987d0SSujith }
1733fb9987d0SSujith 
1734fb9987d0SSujith static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1735fb9987d0SSujith {
1736fb9987d0SSujith 	return 0;
1737fb9987d0SSujith }
1738fb9987d0SSujith 
1739fb9987d0SSujith static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
1740fb9987d0SSujith 					 u8 coverage_class)
1741fb9987d0SSujith {
1742fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
1743fb9987d0SSujith 
1744fb9987d0SSujith 	mutex_lock(&priv->mutex);
1745fb9987d0SSujith 	priv->ah->coverage_class = coverage_class;
1746fb9987d0SSujith 	ath9k_hw_init_global_settings(priv->ah);
1747fb9987d0SSujith 	mutex_unlock(&priv->mutex);
1748fb9987d0SSujith }
1749fb9987d0SSujith 
1750fb9987d0SSujith struct ieee80211_ops ath9k_htc_ops = {
1751fb9987d0SSujith 	.tx                 = ath9k_htc_tx,
1752fb9987d0SSujith 	.start              = ath9k_htc_start,
1753fb9987d0SSujith 	.stop               = ath9k_htc_stop,
1754fb9987d0SSujith 	.add_interface      = ath9k_htc_add_interface,
1755fb9987d0SSujith 	.remove_interface   = ath9k_htc_remove_interface,
1756fb9987d0SSujith 	.config             = ath9k_htc_config,
1757fb9987d0SSujith 	.configure_filter   = ath9k_htc_configure_filter,
1758fb9987d0SSujith 	.sta_notify         = ath9k_htc_sta_notify,
1759fb9987d0SSujith 	.conf_tx            = ath9k_htc_conf_tx,
1760fb9987d0SSujith 	.bss_info_changed   = ath9k_htc_bss_info_changed,
1761fb9987d0SSujith 	.set_key            = ath9k_htc_set_key,
1762fb9987d0SSujith 	.get_tsf            = ath9k_htc_get_tsf,
1763fb9987d0SSujith 	.set_tsf            = ath9k_htc_set_tsf,
1764fb9987d0SSujith 	.reset_tsf          = ath9k_htc_reset_tsf,
1765fb9987d0SSujith 	.ampdu_action       = ath9k_htc_ampdu_action,
1766fb9987d0SSujith 	.sw_scan_start      = ath9k_htc_sw_scan_start,
1767fb9987d0SSujith 	.sw_scan_complete   = ath9k_htc_sw_scan_complete,
1768fb9987d0SSujith 	.set_rts_threshold  = ath9k_htc_set_rts_threshold,
1769fb9987d0SSujith 	.rfkill_poll        = ath9k_htc_rfkill_poll_state,
1770fb9987d0SSujith 	.set_coverage_class = ath9k_htc_set_coverage_class,
1771fb9987d0SSujith };
1772