1fb9987d0SSujith /*
25b68138eSSujith Manoharan  * Copyright (c) 2010-2011 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 
17516304b0SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18516304b0SJoe Perches 
19fb9987d0SSujith #include "htc.h"
20fb9987d0SSujith 
21fb9987d0SSujith MODULE_AUTHOR("Atheros Communications");
22fb9987d0SSujith MODULE_LICENSE("Dual BSD/GPL");
23fb9987d0SSujith MODULE_DESCRIPTION("Atheros driver 802.11n HTC based wireless devices");
24fb9987d0SSujith 
25fb9987d0SSujith static unsigned int ath9k_debug = ATH_DBG_DEFAULT;
26fb9987d0SSujith module_param_named(debug, ath9k_debug, uint, 0);
27fb9987d0SSujith MODULE_PARM_DESC(debug, "Debugging mask");
28fb9987d0SSujith 
29e1572c5eSSujith int htc_modparam_nohwcrypt;
30e1572c5eSSujith module_param_named(nohwcrypt, htc_modparam_nohwcrypt, int, 0444);
31fb9987d0SSujith MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
32fb9987d0SSujith 
337f34778eSMohammed Shafi Shajakhan static int ath9k_htc_btcoex_enable;
347f34778eSMohammed Shafi Shajakhan module_param_named(btcoex_enable, ath9k_htc_btcoex_enable, int, 0444);
357f34778eSMohammed Shafi Shajakhan MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
367f34778eSMohammed Shafi Shajakhan 
376bca610dSOleksij Rempel static int ath9k_ps_enable;
386bca610dSOleksij Rempel module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
396bca610dSOleksij Rempel MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
406bca610dSOleksij Rempel 
41fb9987d0SSujith #define CHAN2G(_freq, _idx)  { \
42fb9987d0SSujith 	.center_freq = (_freq), \
43fb9987d0SSujith 	.hw_value = (_idx), \
44fb9987d0SSujith 	.max_power = 20, \
45fb9987d0SSujith }
46fb9987d0SSujith 
47ea46e644SSujith #define CHAN5G(_freq, _idx) { \
48ea46e644SSujith 	.band = IEEE80211_BAND_5GHZ, \
49ea46e644SSujith 	.center_freq = (_freq), \
50ea46e644SSujith 	.hw_value = (_idx), \
51ea46e644SSujith 	.max_power = 20, \
52ea46e644SSujith }
53ea46e644SSujith 
54fb9987d0SSujith static struct ieee80211_channel ath9k_2ghz_channels[] = {
55fb9987d0SSujith 	CHAN2G(2412, 0), /* Channel 1 */
56fb9987d0SSujith 	CHAN2G(2417, 1), /* Channel 2 */
57fb9987d0SSujith 	CHAN2G(2422, 2), /* Channel 3 */
58fb9987d0SSujith 	CHAN2G(2427, 3), /* Channel 4 */
59fb9987d0SSujith 	CHAN2G(2432, 4), /* Channel 5 */
60fb9987d0SSujith 	CHAN2G(2437, 5), /* Channel 6 */
61fb9987d0SSujith 	CHAN2G(2442, 6), /* Channel 7 */
62fb9987d0SSujith 	CHAN2G(2447, 7), /* Channel 8 */
63fb9987d0SSujith 	CHAN2G(2452, 8), /* Channel 9 */
64fb9987d0SSujith 	CHAN2G(2457, 9), /* Channel 10 */
65fb9987d0SSujith 	CHAN2G(2462, 10), /* Channel 11 */
66fb9987d0SSujith 	CHAN2G(2467, 11), /* Channel 12 */
67fb9987d0SSujith 	CHAN2G(2472, 12), /* Channel 13 */
68fb9987d0SSujith 	CHAN2G(2484, 13), /* Channel 14 */
69fb9987d0SSujith };
70fb9987d0SSujith 
71ea46e644SSujith static struct ieee80211_channel ath9k_5ghz_channels[] = {
72ea46e644SSujith 	/* _We_ call this UNII 1 */
73ea46e644SSujith 	CHAN5G(5180, 14), /* Channel 36 */
74ea46e644SSujith 	CHAN5G(5200, 15), /* Channel 40 */
75ea46e644SSujith 	CHAN5G(5220, 16), /* Channel 44 */
76ea46e644SSujith 	CHAN5G(5240, 17), /* Channel 48 */
77ea46e644SSujith 	/* _We_ call this UNII 2 */
78ea46e644SSujith 	CHAN5G(5260, 18), /* Channel 52 */
79ea46e644SSujith 	CHAN5G(5280, 19), /* Channel 56 */
80ea46e644SSujith 	CHAN5G(5300, 20), /* Channel 60 */
81ea46e644SSujith 	CHAN5G(5320, 21), /* Channel 64 */
82ea46e644SSujith 	/* _We_ call this "Middle band" */
83ea46e644SSujith 	CHAN5G(5500, 22), /* Channel 100 */
84ea46e644SSujith 	CHAN5G(5520, 23), /* Channel 104 */
85ea46e644SSujith 	CHAN5G(5540, 24), /* Channel 108 */
86ea46e644SSujith 	CHAN5G(5560, 25), /* Channel 112 */
87ea46e644SSujith 	CHAN5G(5580, 26), /* Channel 116 */
88ea46e644SSujith 	CHAN5G(5600, 27), /* Channel 120 */
89ea46e644SSujith 	CHAN5G(5620, 28), /* Channel 124 */
90ea46e644SSujith 	CHAN5G(5640, 29), /* Channel 128 */
91ea46e644SSujith 	CHAN5G(5660, 30), /* Channel 132 */
92ea46e644SSujith 	CHAN5G(5680, 31), /* Channel 136 */
93ea46e644SSujith 	CHAN5G(5700, 32), /* Channel 140 */
94ea46e644SSujith 	/* _We_ call this UNII 3 */
95ea46e644SSujith 	CHAN5G(5745, 33), /* Channel 149 */
96ea46e644SSujith 	CHAN5G(5765, 34), /* Channel 153 */
97ea46e644SSujith 	CHAN5G(5785, 35), /* Channel 157 */
98ea46e644SSujith 	CHAN5G(5805, 36), /* Channel 161 */
99ea46e644SSujith 	CHAN5G(5825, 37), /* Channel 165 */
100ea46e644SSujith };
101ea46e644SSujith 
102fb9987d0SSujith /* Atheros hardware rate code addition for short premble */
103fb9987d0SSujith #define SHPCHECK(__hw_rate, __flags) \
104fb9987d0SSujith 	((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0)
105fb9987d0SSujith 
106fb9987d0SSujith #define RATE(_bitrate, _hw_rate, _flags) {		\
107fb9987d0SSujith 	.bitrate	= (_bitrate),			\
108fb9987d0SSujith 	.flags		= (_flags),			\
109fb9987d0SSujith 	.hw_value	= (_hw_rate),			\
110fb9987d0SSujith 	.hw_value_short = (SHPCHECK(_hw_rate, _flags))	\
111fb9987d0SSujith }
112fb9987d0SSujith 
113fb9987d0SSujith static struct ieee80211_rate ath9k_legacy_rates[] = {
114fb9987d0SSujith 	RATE(10, 0x1b, 0),
115fb9987d0SSujith 	RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */
116fb9987d0SSujith 	RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */
117fb9987d0SSujith 	RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */
118fb9987d0SSujith 	RATE(60, 0x0b, 0),
119fb9987d0SSujith 	RATE(90, 0x0f, 0),
120fb9987d0SSujith 	RATE(120, 0x0a, 0),
121fb9987d0SSujith 	RATE(180, 0x0e, 0),
122fb9987d0SSujith 	RATE(240, 0x09, 0),
123fb9987d0SSujith 	RATE(360, 0x0d, 0),
124fb9987d0SSujith 	RATE(480, 0x08, 0),
125fb9987d0SSujith 	RATE(540, 0x0c, 0),
126fb9987d0SSujith };
127fb9987d0SSujith 
128d244f21eSSujith Manoharan #ifdef CONFIG_MAC80211_LEDS
129d244f21eSSujith Manoharan static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
130d244f21eSSujith Manoharan 	{ .throughput = 0 * 1024, .blink_time = 334 },
131d244f21eSSujith Manoharan 	{ .throughput = 1 * 1024, .blink_time = 260 },
132d244f21eSSujith Manoharan 	{ .throughput = 5 * 1024, .blink_time = 220 },
133d244f21eSSujith Manoharan 	{ .throughput = 10 * 1024, .blink_time = 190 },
134d244f21eSSujith Manoharan 	{ .throughput = 20 * 1024, .blink_time = 170 },
135d244f21eSSujith Manoharan 	{ .throughput = 50 * 1024, .blink_time = 150 },
136d244f21eSSujith Manoharan 	{ .throughput = 70 * 1024, .blink_time = 130 },
137d244f21eSSujith Manoharan 	{ .throughput = 100 * 1024, .blink_time = 110 },
138d244f21eSSujith Manoharan 	{ .throughput = 200 * 1024, .blink_time = 80 },
139d244f21eSSujith Manoharan 	{ .throughput = 300 * 1024, .blink_time = 50 },
140d244f21eSSujith Manoharan };
141d244f21eSSujith Manoharan #endif
142d244f21eSSujith Manoharan 
143fb9987d0SSujith static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
144fb9987d0SSujith {
145fb9987d0SSujith 	int time_left;
146fb9987d0SSujith 
147d8c49ffbSSujith.Manoharan@atheros.com 	if (atomic_read(&priv->htc->tgt_ready) > 0) {
148d8c49ffbSSujith.Manoharan@atheros.com 		atomic_dec(&priv->htc->tgt_ready);
149d8c49ffbSSujith.Manoharan@atheros.com 		return 0;
150d8c49ffbSSujith.Manoharan@atheros.com 	}
151d8c49ffbSSujith.Manoharan@atheros.com 
152fb9987d0SSujith 	/* Firmware can take up to 50ms to get ready, to be safe use 1 second */
153fb9987d0SSujith 	time_left = wait_for_completion_timeout(&priv->htc->target_wait, HZ);
154fb9987d0SSujith 	if (!time_left) {
155fb9987d0SSujith 		dev_err(priv->dev, "ath9k_htc: Target is unresponsive\n");
156fb9987d0SSujith 		return -ETIMEDOUT;
157fb9987d0SSujith 	}
158fb9987d0SSujith 
159d8c49ffbSSujith.Manoharan@atheros.com 	atomic_dec(&priv->htc->tgt_ready);
160d8c49ffbSSujith.Manoharan@atheros.com 
161fb9987d0SSujith 	return 0;
162fb9987d0SSujith }
163fb9987d0SSujith 
164fb9987d0SSujith static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
165fb9987d0SSujith {
166fb9987d0SSujith 	ath9k_hw_deinit(priv->ah);
167fb9987d0SSujith 	kfree(priv->ah);
168fb9987d0SSujith 	priv->ah = NULL;
169fb9987d0SSujith }
170fb9987d0SSujith 
171fb9987d0SSujith static void ath9k_deinit_device(struct ath9k_htc_priv *priv)
172fb9987d0SSujith {
173fb9987d0SSujith 	struct ieee80211_hw *hw = priv->hw;
174fb9987d0SSujith 
175fb9987d0SSujith 	wiphy_rfkill_stop_polling(hw->wiphy);
176fb9987d0SSujith 	ath9k_deinit_leds(priv);
177fb9987d0SSujith 	ieee80211_unregister_hw(hw);
178fb9987d0SSujith 	ath9k_rx_cleanup(priv);
179fb9987d0SSujith 	ath9k_tx_cleanup(priv);
180fb9987d0SSujith 	ath9k_deinit_priv(priv);
181fb9987d0SSujith }
182fb9987d0SSujith 
183fb9987d0SSujith static inline int ath9k_htc_connect_svc(struct ath9k_htc_priv *priv,
184fb9987d0SSujith 					u16 service_id,
185fb9987d0SSujith 					void (*tx) (void *,
186fb9987d0SSujith 						    struct sk_buff *,
187fb9987d0SSujith 						    enum htc_endpoint_id,
188fb9987d0SSujith 						    bool txok),
189fb9987d0SSujith 					enum htc_endpoint_id *ep_id)
190fb9987d0SSujith {
191fb9987d0SSujith 	struct htc_service_connreq req;
192fb9987d0SSujith 
193fb9987d0SSujith 	memset(&req, 0, sizeof(struct htc_service_connreq));
194fb9987d0SSujith 
195fb9987d0SSujith 	req.service_id = service_id;
196fb9987d0SSujith 	req.ep_callbacks.priv = priv;
197fb9987d0SSujith 	req.ep_callbacks.rx = ath9k_htc_rxep;
198fb9987d0SSujith 	req.ep_callbacks.tx = tx;
199fb9987d0SSujith 
200fb9987d0SSujith 	return htc_connect_service(priv->htc, &req, ep_id);
201fb9987d0SSujith }
202fb9987d0SSujith 
203fa6e15e0SRajkumar Manoharan static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid,
204fa6e15e0SRajkumar Manoharan 				   u32 drv_info)
205fb9987d0SSujith {
206fb9987d0SSujith 	int ret;
207fb9987d0SSujith 
208fb9987d0SSujith 	/* WMI CMD*/
209fb9987d0SSujith 	ret = ath9k_wmi_connect(priv->htc, priv->wmi, &priv->wmi_cmd_ep);
210fb9987d0SSujith 	if (ret)
211fb9987d0SSujith 		goto err;
212fb9987d0SSujith 
213fb9987d0SSujith 	/* Beacon */
2149c6dda4eSSujith 	ret = ath9k_htc_connect_svc(priv, WMI_BEACON_SVC, ath9k_htc_beaconep,
215fb9987d0SSujith 				    &priv->beacon_ep);
216fb9987d0SSujith 	if (ret)
217fb9987d0SSujith 		goto err;
218fb9987d0SSujith 
219fb9987d0SSujith 	/* CAB */
220fb9987d0SSujith 	ret = ath9k_htc_connect_svc(priv, WMI_CAB_SVC, ath9k_htc_txep,
221fb9987d0SSujith 				    &priv->cab_ep);
222fb9987d0SSujith 	if (ret)
223fb9987d0SSujith 		goto err;
224fb9987d0SSujith 
225fb9987d0SSujith 
226fb9987d0SSujith 	/* UAPSD */
227fb9987d0SSujith 	ret = ath9k_htc_connect_svc(priv, WMI_UAPSD_SVC, ath9k_htc_txep,
228fb9987d0SSujith 				    &priv->uapsd_ep);
229fb9987d0SSujith 	if (ret)
230fb9987d0SSujith 		goto err;
231fb9987d0SSujith 
232fb9987d0SSujith 	/* MGMT */
233fb9987d0SSujith 	ret = ath9k_htc_connect_svc(priv, WMI_MGMT_SVC, ath9k_htc_txep,
234fb9987d0SSujith 				    &priv->mgmt_ep);
235fb9987d0SSujith 	if (ret)
236fb9987d0SSujith 		goto err;
237fb9987d0SSujith 
238fb9987d0SSujith 	/* DATA BE */
239fb9987d0SSujith 	ret = ath9k_htc_connect_svc(priv, WMI_DATA_BE_SVC, ath9k_htc_txep,
240fb9987d0SSujith 				    &priv->data_be_ep);
241fb9987d0SSujith 	if (ret)
242fb9987d0SSujith 		goto err;
243fb9987d0SSujith 
244fb9987d0SSujith 	/* DATA BK */
245fb9987d0SSujith 	ret = ath9k_htc_connect_svc(priv, WMI_DATA_BK_SVC, ath9k_htc_txep,
246fb9987d0SSujith 				    &priv->data_bk_ep);
247fb9987d0SSujith 	if (ret)
248fb9987d0SSujith 		goto err;
249fb9987d0SSujith 
250fb9987d0SSujith 	/* DATA VI */
251fb9987d0SSujith 	ret = ath9k_htc_connect_svc(priv, WMI_DATA_VI_SVC, ath9k_htc_txep,
252fb9987d0SSujith 				    &priv->data_vi_ep);
253fb9987d0SSujith 	if (ret)
254fb9987d0SSujith 		goto err;
255fb9987d0SSujith 
256fb9987d0SSujith 	/* DATA VO */
257fb9987d0SSujith 	ret = ath9k_htc_connect_svc(priv, WMI_DATA_VO_SVC, ath9k_htc_txep,
258fb9987d0SSujith 				    &priv->data_vo_ep);
259fb9987d0SSujith 	if (ret)
260fb9987d0SSujith 		goto err;
261fb9987d0SSujith 
2626267dc70SSujith 	/*
2636267dc70SSujith 	 * Setup required credits before initializing HTC.
2646267dc70SSujith 	 * This is a bit hacky, but, since queuing is done in
2656267dc70SSujith 	 * the HIF layer, shouldn't matter much.
2666267dc70SSujith 	 */
2676267dc70SSujith 
2680b5ead91SSujith Manoharan 	if (IS_AR7010_DEVICE(drv_info))
269d108e8b9SSujith Manoharan 		priv->htc->credits = 45;
270fa6e15e0SRajkumar Manoharan 	else
2714e63f768SSujith 		priv->htc->credits = 33;
2726267dc70SSujith 
273fb9987d0SSujith 	ret = htc_init(priv->htc);
274fb9987d0SSujith 	if (ret)
275fb9987d0SSujith 		goto err;
276fb9987d0SSujith 
2776267dc70SSujith 	dev_info(priv->dev, "ath9k_htc: HTC initialized with %d credits\n",
2786267dc70SSujith 		 priv->htc->credits);
2796267dc70SSujith 
280fb9987d0SSujith 	return 0;
281fb9987d0SSujith 
282fb9987d0SSujith err:
283fb9987d0SSujith 	dev_err(priv->dev, "ath9k_htc: Unable to initialize HTC services\n");
284fb9987d0SSujith 	return ret;
285fb9987d0SSujith }
286fb9987d0SSujith 
2870c0280bdSLuis R. Rodriguez static void ath9k_reg_notifier(struct wiphy *wiphy,
288fb9987d0SSujith 			       struct regulatory_request *request)
289fb9987d0SSujith {
290fb9987d0SSujith 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
291fb9987d0SSujith 	struct ath9k_htc_priv *priv = hw->priv;
292fb9987d0SSujith 
2930c0280bdSLuis R. Rodriguez 	ath_reg_notifier_apply(wiphy, request,
294fb9987d0SSujith 			       ath9k_hw_regulatory(priv->ah));
295fb9987d0SSujith }
296fb9987d0SSujith 
2974a22fe10SSujith static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
298fb9987d0SSujith {
299fb9987d0SSujith 	struct ath_hw *ah = (struct ath_hw *) hw_priv;
300fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(ah);
301fb9987d0SSujith 	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
302fb9987d0SSujith 	__be32 val, reg = cpu_to_be32(reg_offset);
303fb9987d0SSujith 	int r;
304fb9987d0SSujith 
305fb9987d0SSujith 	r = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID,
306fb9987d0SSujith 			  (u8 *) &reg, sizeof(reg),
307fb9987d0SSujith 			  (u8 *) &val, sizeof(val),
308fb9987d0SSujith 			  100);
309fb9987d0SSujith 	if (unlikely(r)) {
310d2182b69SJoe Perches 		ath_dbg(common, WMI, "REGISTER READ FAILED: (0x%04x, %d)\n",
311fb9987d0SSujith 			reg_offset, r);
312fb9987d0SSujith 		return -EIO;
313fb9987d0SSujith 	}
314fb9987d0SSujith 
315fb9987d0SSujith 	return be32_to_cpu(val);
316fb9987d0SSujith }
317fb9987d0SSujith 
31809a525d3SSujith Manoharan static void ath9k_multi_regread(void *hw_priv, u32 *addr,
31909a525d3SSujith Manoharan 				u32 *val, u16 count)
32009a525d3SSujith Manoharan {
32109a525d3SSujith Manoharan 	struct ath_hw *ah = (struct ath_hw *) hw_priv;
32209a525d3SSujith Manoharan 	struct ath_common *common = ath9k_hw_common(ah);
32309a525d3SSujith Manoharan 	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
32409a525d3SSujith Manoharan 	__be32 tmpaddr[8];
32509a525d3SSujith Manoharan 	__be32 tmpval[8];
32609a525d3SSujith Manoharan 	int i, ret;
32709a525d3SSujith Manoharan 
32809a525d3SSujith Manoharan        for (i = 0; i < count; i++) {
32909a525d3SSujith Manoharan 	       tmpaddr[i] = cpu_to_be32(addr[i]);
33009a525d3SSujith Manoharan        }
33109a525d3SSujith Manoharan 
33209a525d3SSujith Manoharan        ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID,
33309a525d3SSujith Manoharan 			   (u8 *)tmpaddr , sizeof(u32) * count,
33409a525d3SSujith Manoharan 			   (u8 *)tmpval, sizeof(u32) * count,
33509a525d3SSujith Manoharan 			   100);
33609a525d3SSujith Manoharan 	if (unlikely(ret)) {
337d2182b69SJoe Perches 		ath_dbg(common, WMI,
33809a525d3SSujith Manoharan 			"Multiple REGISTER READ FAILED (count: %d)\n", count);
33909a525d3SSujith Manoharan 	}
34009a525d3SSujith Manoharan 
34109a525d3SSujith Manoharan        for (i = 0; i < count; i++) {
34209a525d3SSujith Manoharan 	       val[i] = be32_to_cpu(tmpval[i]);
34309a525d3SSujith Manoharan        }
34409a525d3SSujith Manoharan }
34509a525d3SSujith Manoharan 
3464a22fe10SSujith static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
347fb9987d0SSujith {
348fb9987d0SSujith 	struct ath_hw *ah = (struct ath_hw *) hw_priv;
349fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(ah);
350fb9987d0SSujith 	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
35107b2fa5aSJoe Perches 	const __be32 buf[2] = {
352fb9987d0SSujith 		cpu_to_be32(reg_offset),
353fb9987d0SSujith 		cpu_to_be32(val),
354fb9987d0SSujith 	};
355fb9987d0SSujith 	int r;
356fb9987d0SSujith 
357fb9987d0SSujith 	r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
358fb9987d0SSujith 			  (u8 *) &buf, sizeof(buf),
359fb9987d0SSujith 			  (u8 *) &val, sizeof(val),
360fb9987d0SSujith 			  100);
361fb9987d0SSujith 	if (unlikely(r)) {
362d2182b69SJoe Perches 		ath_dbg(common, WMI, "REGISTER WRITE FAILED:(0x%04x, %d)\n",
363fb9987d0SSujith 			reg_offset, r);
364fb9987d0SSujith 	}
365fb9987d0SSujith }
366fb9987d0SSujith 
3674a22fe10SSujith static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
3684a22fe10SSujith {
3694a22fe10SSujith 	struct ath_hw *ah = (struct ath_hw *) hw_priv;
3704a22fe10SSujith 	struct ath_common *common = ath9k_hw_common(ah);
3714a22fe10SSujith 	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
3724a22fe10SSujith 	u32 rsp_status;
3734a22fe10SSujith 	int r;
3744a22fe10SSujith 
3754a22fe10SSujith 	mutex_lock(&priv->wmi->multi_write_mutex);
3764a22fe10SSujith 
3774a22fe10SSujith 	/* Store the register/value */
3784a22fe10SSujith 	priv->wmi->multi_write[priv->wmi->multi_write_idx].reg =
3794a22fe10SSujith 		cpu_to_be32(reg_offset);
3804a22fe10SSujith 	priv->wmi->multi_write[priv->wmi->multi_write_idx].val =
3814a22fe10SSujith 		cpu_to_be32(val);
3824a22fe10SSujith 
3834a22fe10SSujith 	priv->wmi->multi_write_idx++;
3844a22fe10SSujith 
3854a22fe10SSujith 	/* If the buffer is full, send it out. */
3864a22fe10SSujith 	if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) {
3874a22fe10SSujith 		r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
3884a22fe10SSujith 			  (u8 *) &priv->wmi->multi_write,
3894a22fe10SSujith 			  sizeof(struct register_write) * priv->wmi->multi_write_idx,
3904a22fe10SSujith 			  (u8 *) &rsp_status, sizeof(rsp_status),
3914a22fe10SSujith 			  100);
3924a22fe10SSujith 		if (unlikely(r)) {
393d2182b69SJoe Perches 			ath_dbg(common, WMI,
3944a22fe10SSujith 				"REGISTER WRITE FAILED, multi len: %d\n",
3954a22fe10SSujith 				priv->wmi->multi_write_idx);
3964a22fe10SSujith 		}
3974a22fe10SSujith 		priv->wmi->multi_write_idx = 0;
3984a22fe10SSujith 	}
3994a22fe10SSujith 
4004a22fe10SSujith 	mutex_unlock(&priv->wmi->multi_write_mutex);
4014a22fe10SSujith }
4024a22fe10SSujith 
4034a22fe10SSujith static void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset)
4044a22fe10SSujith {
4054a22fe10SSujith 	struct ath_hw *ah = (struct ath_hw *) hw_priv;
4064a22fe10SSujith 	struct ath_common *common = ath9k_hw_common(ah);
4074a22fe10SSujith 	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
4084a22fe10SSujith 
4094a22fe10SSujith 	if (atomic_read(&priv->wmi->mwrite_cnt))
4104a22fe10SSujith 		ath9k_regwrite_buffer(hw_priv, val, reg_offset);
4114a22fe10SSujith 	else
4124a22fe10SSujith 		ath9k_regwrite_single(hw_priv, val, reg_offset);
4134a22fe10SSujith }
4144a22fe10SSujith 
4154a22fe10SSujith static void ath9k_enable_regwrite_buffer(void *hw_priv)
4164a22fe10SSujith {
4174a22fe10SSujith 	struct ath_hw *ah = (struct ath_hw *) hw_priv;
4184a22fe10SSujith 	struct ath_common *common = ath9k_hw_common(ah);
4194a22fe10SSujith 	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
4204a22fe10SSujith 
4214a22fe10SSujith 	atomic_inc(&priv->wmi->mwrite_cnt);
4224a22fe10SSujith }
4234a22fe10SSujith 
4244a22fe10SSujith static void ath9k_regwrite_flush(void *hw_priv)
4254a22fe10SSujith {
4264a22fe10SSujith 	struct ath_hw *ah = (struct ath_hw *) hw_priv;
4274a22fe10SSujith 	struct ath_common *common = ath9k_hw_common(ah);
4284a22fe10SSujith 	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
4294a22fe10SSujith 	u32 rsp_status;
4304a22fe10SSujith 	int r;
4314a22fe10SSujith 
432435c1610SFelix Fietkau 	atomic_dec(&priv->wmi->mwrite_cnt);
433435c1610SFelix Fietkau 
4344a22fe10SSujith 	mutex_lock(&priv->wmi->multi_write_mutex);
4354a22fe10SSujith 
4364a22fe10SSujith 	if (priv->wmi->multi_write_idx) {
4374a22fe10SSujith 		r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
4384a22fe10SSujith 			  (u8 *) &priv->wmi->multi_write,
4394a22fe10SSujith 			  sizeof(struct register_write) * priv->wmi->multi_write_idx,
4404a22fe10SSujith 			  (u8 *) &rsp_status, sizeof(rsp_status),
4414a22fe10SSujith 			  100);
4424a22fe10SSujith 		if (unlikely(r)) {
443d2182b69SJoe Perches 			ath_dbg(common, WMI,
4444a22fe10SSujith 				"REGISTER WRITE FAILED, multi len: %d\n",
4454a22fe10SSujith 				priv->wmi->multi_write_idx);
4464a22fe10SSujith 		}
4474a22fe10SSujith 		priv->wmi->multi_write_idx = 0;
4484a22fe10SSujith 	}
4494a22fe10SSujith 
4504a22fe10SSujith 	mutex_unlock(&priv->wmi->multi_write_mutex);
4514a22fe10SSujith }
4524a22fe10SSujith 
453845e03c9SFelix Fietkau static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
454845e03c9SFelix Fietkau {
455845e03c9SFelix Fietkau 	u32 val;
456845e03c9SFelix Fietkau 
457845e03c9SFelix Fietkau 	val = ath9k_regread(hw_priv, reg_offset);
458845e03c9SFelix Fietkau 	val &= ~clr;
459845e03c9SFelix Fietkau 	val |= set;
460845e03c9SFelix Fietkau 	ath9k_regwrite(hw_priv, val, reg_offset);
461845e03c9SFelix Fietkau 	return val;
462845e03c9SFelix Fietkau }
463845e03c9SFelix Fietkau 
464fb9987d0SSujith static void ath_usb_read_cachesize(struct ath_common *common, int *csz)
465fb9987d0SSujith {
466fb9987d0SSujith 	*csz = L1_CACHE_BYTES >> 2;
467fb9987d0SSujith }
468fb9987d0SSujith 
469fb9987d0SSujith static bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
470fb9987d0SSujith {
471fb9987d0SSujith 	struct ath_hw *ah = (struct ath_hw *) common->ah;
472fb9987d0SSujith 
473fb9987d0SSujith 	(void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
474fb9987d0SSujith 
475fb9987d0SSujith 	if (!ath9k_hw_wait(ah,
476fb9987d0SSujith 			   AR_EEPROM_STATUS_DATA,
477fb9987d0SSujith 			   AR_EEPROM_STATUS_DATA_BUSY |
478fb9987d0SSujith 			   AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
479fb9987d0SSujith 			   AH_WAIT_TIMEOUT))
480fb9987d0SSujith 		return false;
481fb9987d0SSujith 
482fb9987d0SSujith 	*data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
483fb9987d0SSujith 		   AR_EEPROM_STATUS_DATA_VAL);
484fb9987d0SSujith 
485fb9987d0SSujith 	return true;
486fb9987d0SSujith }
487fb9987d0SSujith 
488fb9987d0SSujith static const struct ath_bus_ops ath9k_usb_bus_ops = {
489497ad9adSSujith 	.ath_bus_type = ATH_USB,
490fb9987d0SSujith 	.read_cachesize = ath_usb_read_cachesize,
491fb9987d0SSujith 	.eeprom_read = ath_usb_eeprom_read,
492fb9987d0SSujith };
493fb9987d0SSujith 
494fb9987d0SSujith static void setup_ht_cap(struct ath9k_htc_priv *priv,
495fb9987d0SSujith 			 struct ieee80211_sta_ht_cap *ht_info)
496fb9987d0SSujith {
4976debecadSSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
4986debecadSSujith 	u8 tx_streams, rx_streams;
4996debecadSSujith 	int i;
5006debecadSSujith 
501fb9987d0SSujith 	ht_info->ht_supported = true;
502fb9987d0SSujith 	ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
503fb9987d0SSujith 		       IEEE80211_HT_CAP_SM_PS |
504fb9987d0SSujith 		       IEEE80211_HT_CAP_SGI_40 |
505fb9987d0SSujith 		       IEEE80211_HT_CAP_DSSSCCK40;
506fb9987d0SSujith 
507b4dec5e8SSujith 	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
508b4dec5e8SSujith 		ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
509b4dec5e8SSujith 
51017525f96SSujith 	ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
51117525f96SSujith 
512fb9987d0SSujith 	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
513fb9987d0SSujith 	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
514fb9987d0SSujith 
515fb9987d0SSujith 	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
5166debecadSSujith 
5176debecadSSujith 	/* ath9k_htc supports only 1 or 2 stream devices */
51882b2d334SFelix Fietkau 	tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2);
51982b2d334SFelix Fietkau 	rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2);
5206debecadSSujith 
521d2182b69SJoe Perches 	ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n",
5226debecadSSujith 		tx_streams, rx_streams);
5236debecadSSujith 
524a226c3d9SOleksij Rempel 	if (tx_streams >= 2)
525a226c3d9SOleksij Rempel 		ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
526a226c3d9SOleksij Rempel 
5276debecadSSujith 	if (tx_streams != rx_streams) {
5286debecadSSujith 		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
5296debecadSSujith 		ht_info->mcs.tx_params |= ((tx_streams - 1) <<
5306debecadSSujith 					   IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
5316debecadSSujith 	}
5326debecadSSujith 
5336debecadSSujith 	for (i = 0; i < rx_streams; i++)
5346debecadSSujith 		ht_info->mcs.rx_mask[i] = 0xff;
5356debecadSSujith 
536fb9987d0SSujith 	ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
537fb9987d0SSujith }
538fb9987d0SSujith 
539fb9987d0SSujith static int ath9k_init_queues(struct ath9k_htc_priv *priv)
540fb9987d0SSujith {
541fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
542fb9987d0SSujith 	int i;
543fb9987d0SSujith 
544fb9987d0SSujith 	for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++)
545fb9987d0SSujith 		priv->hwq_map[i] = -1;
546fb9987d0SSujith 
547ca74b83bSSujith 	priv->beaconq = ath9k_hw_beaconq_setup(priv->ah);
548ca74b83bSSujith 	if (priv->beaconq == -1) {
5493800276aSJoe Perches 		ath_err(common, "Unable to setup BEACON xmit queue\n");
550ca74b83bSSujith 		goto err;
551ca74b83bSSujith 	}
552ca74b83bSSujith 
553ca74b83bSSujith 	priv->cabq = ath9k_htc_cabq_setup(priv);
554ca74b83bSSujith 	if (priv->cabq == -1) {
5553800276aSJoe Perches 		ath_err(common, "Unable to setup CAB xmit queue\n");
556ca74b83bSSujith 		goto err;
557ca74b83bSSujith 	}
558ca74b83bSSujith 
559bea843c7SSujith Manoharan 	if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_BE)) {
5603800276aSJoe Perches 		ath_err(common, "Unable to setup xmit queue for BE traffic\n");
561fb9987d0SSujith 		goto err;
562fb9987d0SSujith 	}
563fb9987d0SSujith 
564bea843c7SSujith Manoharan 	if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_BK)) {
5653800276aSJoe Perches 		ath_err(common, "Unable to setup xmit queue for BK traffic\n");
566fb9987d0SSujith 		goto err;
567fb9987d0SSujith 	}
568bea843c7SSujith Manoharan 	if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_VI)) {
5693800276aSJoe Perches 		ath_err(common, "Unable to setup xmit queue for VI traffic\n");
570fb9987d0SSujith 		goto err;
571fb9987d0SSujith 	}
572bea843c7SSujith Manoharan 	if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_VO)) {
5733800276aSJoe Perches 		ath_err(common, "Unable to setup xmit queue for VO traffic\n");
574fb9987d0SSujith 		goto err;
575fb9987d0SSujith 	}
576fb9987d0SSujith 
577fb9987d0SSujith 	return 0;
578fb9987d0SSujith 
579fb9987d0SSujith err:
580fb9987d0SSujith 	return -EINVAL;
581fb9987d0SSujith }
582fb9987d0SSujith 
583fb9987d0SSujith static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
584fb9987d0SSujith {
585d4659912SFelix Fietkau 	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
586fb9987d0SSujith 		priv->sbands[IEEE80211_BAND_2GHZ].channels =
587fb9987d0SSujith 			ath9k_2ghz_channels;
588fb9987d0SSujith 		priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
589fb9987d0SSujith 		priv->sbands[IEEE80211_BAND_2GHZ].n_channels =
590fb9987d0SSujith 			ARRAY_SIZE(ath9k_2ghz_channels);
591fb9987d0SSujith 		priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
592fb9987d0SSujith 		priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
593fb9987d0SSujith 			ARRAY_SIZE(ath9k_legacy_rates);
594fb9987d0SSujith 	}
595ea46e644SSujith 
596d4659912SFelix Fietkau 	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
597ea46e644SSujith 		priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels;
598ea46e644SSujith 		priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
599ea46e644SSujith 		priv->sbands[IEEE80211_BAND_5GHZ].n_channels =
600ea46e644SSujith 			ARRAY_SIZE(ath9k_5ghz_channels);
601ea46e644SSujith 		priv->sbands[IEEE80211_BAND_5GHZ].bitrates =
602ea46e644SSujith 			ath9k_legacy_rates + 4;
603ea46e644SSujith 		priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
604ea46e644SSujith 			ARRAY_SIZE(ath9k_legacy_rates) - 4;
605ea46e644SSujith 	}
606fb9987d0SSujith }
607fb9987d0SSujith 
608fb9987d0SSujith static void ath9k_init_misc(struct ath9k_htc_priv *priv)
609fb9987d0SSujith {
610fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
611fb9987d0SSujith 
612fb9987d0SSujith 	memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
613fb9987d0SSujith 
6149f01a84eSSujith 	priv->ah->opmode = NL80211_IFTYPE_STATION;
615fb9987d0SSujith }
616fb9987d0SSujith 
61721cb9879SVivek Natarajan static int ath9k_init_priv(struct ath9k_htc_priv *priv,
618fa6e15e0SRajkumar Manoharan 			   u16 devid, char *product,
619fa6e15e0SRajkumar Manoharan 			   u32 drv_info)
620fb9987d0SSujith {
621fb9987d0SSujith 	struct ath_hw *ah = NULL;
622fb9987d0SSujith 	struct ath_common *common;
623832f6a18SSujith Manoharan 	int i, ret = 0, csz = 0;
624fb9987d0SSujith 
625d8a2c51cSSujith Manoharan 	set_bit(OP_INVALID, &priv->op_flags);
626fb9987d0SSujith 
627fb9987d0SSujith 	ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
628fb9987d0SSujith 	if (!ah)
629fb9987d0SSujith 		return -ENOMEM;
630fb9987d0SSujith 
631fb9987d0SSujith 	ah->hw_version.devid = devid;
6320b5ead91SSujith Manoharan 	ah->hw_version.usbdev = drv_info;
633f8afa42bSFelix Fietkau 	ah->ah_flags |= AH_USE_EEPROM;
634f9f84e96SFelix Fietkau 	ah->reg_ops.read = ath9k_regread;
635f9f84e96SFelix Fietkau 	ah->reg_ops.multi_read = ath9k_multi_regread;
636f9f84e96SFelix Fietkau 	ah->reg_ops.write = ath9k_regwrite;
637f9f84e96SFelix Fietkau 	ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer;
638f9f84e96SFelix Fietkau 	ah->reg_ops.write_flush = ath9k_regwrite_flush;
639845e03c9SFelix Fietkau 	ah->reg_ops.rmw = ath9k_reg_rmw;
640fb9987d0SSujith 	priv->ah = ah;
641fb9987d0SSujith 
642fb9987d0SSujith 	common = ath9k_hw_common(ah);
643f9f84e96SFelix Fietkau 	common->ops = &ah->reg_ops;
644fb9987d0SSujith 	common->bus_ops = &ath9k_usb_bus_ops;
645fb9987d0SSujith 	common->ah = ah;
646fb9987d0SSujith 	common->hw = priv->hw;
647fb9987d0SSujith 	common->priv = priv;
648fb9987d0SSujith 	common->debug_mask = ath9k_debug;
6497f34778eSMohammed Shafi Shajakhan 	common->btcoex_enabled = ath9k_htc_btcoex_enable == 1;
650fb9987d0SSujith 
651fb9987d0SSujith 	spin_lock_init(&priv->beacon_lock);
652658ef04fSSujith Manoharan 	spin_lock_init(&priv->tx.tx_lock);
653fb9987d0SSujith 	mutex_init(&priv->mutex);
654bde748a4SVivek Natarajan 	mutex_init(&priv->htc_pm_lock);
655fb9987d0SSujith 	tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
656fb9987d0SSujith 		     (unsigned long)priv);
65727876a29SSujith Manoharan 	tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet,
65873908674SSujith Manoharan 		     (unsigned long)priv);
659a236254cSSujith Manoharan 	INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work);
660bde748a4SVivek Natarajan 	INIT_WORK(&priv->ps_work, ath9k_ps_work);
66173908674SSujith Manoharan 	INIT_WORK(&priv->fatal_work, ath9k_fatal_work);
662859c3ca1SSujith Manoharan 	setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer,
663859c3ca1SSujith Manoharan 		    (unsigned long)priv);
664fb9987d0SSujith 
665fb9987d0SSujith 	/*
666fb9987d0SSujith 	 * Cache line size is used to size and align various
667fb9987d0SSujith 	 * structures used to communicate with the hardware.
668fb9987d0SSujith 	 */
669fb9987d0SSujith 	ath_read_cachesize(common, &csz);
670fb9987d0SSujith 	common->cachelsz = csz << 2; /* convert to bytes */
671fb9987d0SSujith 
672fb9987d0SSujith 	ret = ath9k_hw_init(ah);
673fb9987d0SSujith 	if (ret) {
6743800276aSJoe Perches 		ath_err(common,
6753800276aSJoe Perches 			"Unable to initialize hardware; initialization status: %d\n",
6763800276aSJoe Perches 			ret);
677fb9987d0SSujith 		goto err_hw;
678fb9987d0SSujith 	}
679fb9987d0SSujith 
680fb9987d0SSujith 	ret = ath9k_init_queues(priv);
681fb9987d0SSujith 	if (ret)
682fb9987d0SSujith 		goto err_queues;
683fb9987d0SSujith 
684832f6a18SSujith Manoharan 	for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
685832f6a18SSujith Manoharan 		priv->cur_beacon_conf.bslot[i] = NULL;
686832f6a18SSujith Manoharan 
687f82b4bdeSRajkumar Manoharan 	ath9k_cmn_init_crypto(ah);
688fb9987d0SSujith 	ath9k_init_channels_rates(priv);
689fb9987d0SSujith 	ath9k_init_misc(priv);
690cee5341dSSujith Manoharan 	ath9k_htc_init_btcoex(priv, product);
69121cb9879SVivek Natarajan 
692fb9987d0SSujith 	return 0;
693fb9987d0SSujith 
694fb9987d0SSujith err_queues:
695fb9987d0SSujith 	ath9k_hw_deinit(ah);
696fb9987d0SSujith err_hw:
697fb9987d0SSujith 
698fb9987d0SSujith 	kfree(ah);
699fb9987d0SSujith 	priv->ah = NULL;
700fb9987d0SSujith 
701fb9987d0SSujith 	return ret;
702fb9987d0SSujith }
703fb9987d0SSujith 
7048b0b6be5SMohammed Shafi Shajakhan static const struct ieee80211_iface_limit if_limits[] = {
7058b0b6be5SMohammed Shafi Shajakhan 	{ .max = 2,	.types = BIT(NL80211_IFTYPE_STATION) |
7068b0b6be5SMohammed Shafi Shajakhan 				 BIT(NL80211_IFTYPE_P2P_CLIENT) },
7078b0b6be5SMohammed Shafi Shajakhan 	{ .max = 2,	.types = BIT(NL80211_IFTYPE_AP) |
7080c9acaa8SThomas Pedersen #ifdef CONFIG_MAC80211_MESH
7090c9acaa8SThomas Pedersen 				 BIT(NL80211_IFTYPE_MESH_POINT) |
7100c9acaa8SThomas Pedersen #endif
7110c9acaa8SThomas Pedersen 				 BIT(NL80211_IFTYPE_P2P_GO) },
7128b0b6be5SMohammed Shafi Shajakhan };
7138b0b6be5SMohammed Shafi Shajakhan 
7148b0b6be5SMohammed Shafi Shajakhan static const struct ieee80211_iface_combination if_comb = {
7158b0b6be5SMohammed Shafi Shajakhan 	.limits = if_limits,
7168b0b6be5SMohammed Shafi Shajakhan 	.n_limits = ARRAY_SIZE(if_limits),
7178b0b6be5SMohammed Shafi Shajakhan 	.max_interfaces = 2,
7188b0b6be5SMohammed Shafi Shajakhan 	.num_different_channels = 1,
7198b0b6be5SMohammed Shafi Shajakhan };
7208b0b6be5SMohammed Shafi Shajakhan 
721fb9987d0SSujith static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
722fb9987d0SSujith 			       struct ieee80211_hw *hw)
723fb9987d0SSujith {
724fb9987d0SSujith 	struct ath_common *common = ath9k_hw_common(priv->ah);
725156652bbSBen Greear 	struct base_eep_header *pBase;
726fb9987d0SSujith 
727fb9987d0SSujith 	hw->flags = IEEE80211_HW_SIGNAL_DBM |
728fb9987d0SSujith 		IEEE80211_HW_AMPDU_AGGREGATION |
729fb9987d0SSujith 		IEEE80211_HW_SPECTRUM_MGMT |
73032fbccafSSujith 		IEEE80211_HW_HAS_RATE_CONTROL |
731bde748a4SVivek Natarajan 		IEEE80211_HW_RX_INCLUDES_FCS |
7327d547eb4SSujith Manoharan 		IEEE80211_HW_PS_NULLFUNC_STACK |
7338ae2e12fSRajkumar Manoharan 		IEEE80211_HW_REPORTS_TX_ACK_STATUS |
734bd4a85eeSJavier Cardona 		IEEE80211_HW_MFP_CAPABLE |
7357d547eb4SSujith Manoharan 		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
736fb9987d0SSujith 
7376bca610dSOleksij Rempel 	if (ath9k_ps_enable)
7386bca610dSOleksij Rempel 		hw->flags |= IEEE80211_HW_SUPPORTS_PS;
7396bca610dSOleksij Rempel 
740fb9987d0SSujith 	hw->wiphy->interface_modes =
741fb9987d0SSujith 		BIT(NL80211_IFTYPE_STATION) |
74209d5b94dSSujith Manoharan 		BIT(NL80211_IFTYPE_ADHOC) |
74309d5b94dSSujith Manoharan 		BIT(NL80211_IFTYPE_AP) |
74409d5b94dSSujith Manoharan 		BIT(NL80211_IFTYPE_P2P_GO) |
745594e65b6SJavier Cardona 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
746594e65b6SJavier Cardona 		BIT(NL80211_IFTYPE_MESH_POINT);
747fb9987d0SSujith 
7488b0b6be5SMohammed Shafi Shajakhan 	hw->wiphy->iface_combinations = &if_comb;
7498b0b6be5SMohammed Shafi Shajakhan 	hw->wiphy->n_iface_combinations = 1;
7508b0b6be5SMohammed Shafi Shajakhan 
751bde748a4SVivek Natarajan 	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
752bde748a4SVivek Natarajan 
75381ddbb5cSJohannes Berg 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN |
75481ddbb5cSJohannes Berg 			    WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
755d7d312caSAntonio Quartulli 
756fb9987d0SSujith 	hw->queues = 4;
757fb1c078eSSujith Manoharan 	hw->max_listen_interval = 1;
7583a0593efSSujith Manoharan 
759fb9987d0SSujith 	hw->vif_data_size = sizeof(struct ath9k_htc_vif);
760fb9987d0SSujith 	hw->sta_data_size = sizeof(struct ath9k_htc_sta);
761fb9987d0SSujith 
762fb9987d0SSujith 	/* tx_frame_hdr is larger than tx_mgmt_hdr anyway */
763fb9987d0SSujith 	hw->extra_tx_headroom = sizeof(struct tx_frame_hdr) +
764fb9987d0SSujith 		sizeof(struct htc_frame_hdr) + 4;
765fb9987d0SSujith 
766d4659912SFelix Fietkau 	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
767fb9987d0SSujith 		hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
768fb9987d0SSujith 			&priv->sbands[IEEE80211_BAND_2GHZ];
769d4659912SFelix Fietkau 	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
770ea46e644SSujith 		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
771ea46e644SSujith 			&priv->sbands[IEEE80211_BAND_5GHZ];
772fb9987d0SSujith 
773fb9987d0SSujith 	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
774d4659912SFelix Fietkau 		if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
775fb9987d0SSujith 			setup_ht_cap(priv,
776fb9987d0SSujith 				     &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap);
777d4659912SFelix Fietkau 		if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
778ea46e644SSujith 			setup_ht_cap(priv,
779ea46e644SSujith 				     &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap);
780fb9987d0SSujith 	}
781fb9987d0SSujith 
782156652bbSBen Greear 	pBase = ath9k_htc_get_eeprom_base(priv);
783156652bbSBen Greear 	if (pBase) {
784156652bbSBen Greear 		hw->wiphy->available_antennas_rx = pBase->rxMask;
785156652bbSBen Greear 		hw->wiphy->available_antennas_tx = pBase->txMask;
786156652bbSBen Greear 	}
787156652bbSBen Greear 
788fb9987d0SSujith 	SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
789fb9987d0SSujith }
790fb9987d0SSujith 
79129bbfb24SSujith Manoharan static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
79229bbfb24SSujith Manoharan {
79329bbfb24SSujith Manoharan 	struct ieee80211_hw *hw = priv->hw;
79429bbfb24SSujith Manoharan 	struct wmi_fw_version cmd_rsp;
79529bbfb24SSujith Manoharan 	int ret;
79629bbfb24SSujith Manoharan 
79729bbfb24SSujith Manoharan 	memset(&cmd_rsp, 0, sizeof(cmd_rsp));
79829bbfb24SSujith Manoharan 
79929bbfb24SSujith Manoharan 	WMI_CMD(WMI_GET_FW_VERSION);
80029bbfb24SSujith Manoharan 	if (ret)
80129bbfb24SSujith Manoharan 		return -EINVAL;
80229bbfb24SSujith Manoharan 
80329bbfb24SSujith Manoharan 	priv->fw_version_major = be16_to_cpu(cmd_rsp.major);
80429bbfb24SSujith Manoharan 	priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor);
80529bbfb24SSujith Manoharan 
80681135548SJiri Pirko 	snprintf(hw->wiphy->fw_version, sizeof(hw->wiphy->fw_version), "%d.%d",
80729bbfb24SSujith Manoharan 		 priv->fw_version_major,
80829bbfb24SSujith Manoharan 		 priv->fw_version_minor);
80929bbfb24SSujith Manoharan 
81029bbfb24SSujith Manoharan 	dev_info(priv->dev, "ath9k_htc: FW Version: %d.%d\n",
81129bbfb24SSujith Manoharan 		 priv->fw_version_major,
81229bbfb24SSujith Manoharan 		 priv->fw_version_minor);
81329bbfb24SSujith Manoharan 
8143a0593efSSujith Manoharan 	/*
8153a0593efSSujith Manoharan 	 * Check if the available FW matches the driver's
8163a0593efSSujith Manoharan 	 * required version.
8173a0593efSSujith Manoharan 	 */
8183a0593efSSujith Manoharan 	if (priv->fw_version_major != MAJOR_VERSION_REQ ||
819319e7bd9SFelix Fietkau 	    priv->fw_version_minor < MINOR_VERSION_REQ) {
8203a0593efSSujith Manoharan 		dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n",
8213a0593efSSujith Manoharan 			MAJOR_VERSION_REQ, MINOR_VERSION_REQ);
8223a0593efSSujith Manoharan 		return -EINVAL;
8233a0593efSSujith Manoharan 	}
8243a0593efSSujith Manoharan 
82529bbfb24SSujith Manoharan 	return 0;
82629bbfb24SSujith Manoharan }
82729bbfb24SSujith Manoharan 
82821cb9879SVivek Natarajan static int ath9k_init_device(struct ath9k_htc_priv *priv,
829fa6e15e0SRajkumar Manoharan 			     u16 devid, char *product, u32 drv_info)
830fb9987d0SSujith {
831fb9987d0SSujith 	struct ieee80211_hw *hw = priv->hw;
832fb9987d0SSujith 	struct ath_common *common;
833fb9987d0SSujith 	struct ath_hw *ah;
834fb9987d0SSujith 	int error = 0;
835fb9987d0SSujith 	struct ath_regulatory *reg;
8363e3f1d19SSujith Manoharan 	char hw_name[64];
837fb9987d0SSujith 
838fb9987d0SSujith 	/* Bring up device */
839fa6e15e0SRajkumar Manoharan 	error = ath9k_init_priv(priv, devid, product, drv_info);
840fb9987d0SSujith 	if (error != 0)
841fb9987d0SSujith 		goto err_init;
842fb9987d0SSujith 
843fb9987d0SSujith 	ah = priv->ah;
844fb9987d0SSujith 	common = ath9k_hw_common(ah);
845fb9987d0SSujith 	ath9k_set_hw_capab(priv, hw);
846fb9987d0SSujith 
84729bbfb24SSujith Manoharan 	error = ath9k_init_firmware_version(priv);
84829bbfb24SSujith Manoharan 	if (error != 0)
84929bbfb24SSujith Manoharan 		goto err_fw;
85029bbfb24SSujith Manoharan 
851fb9987d0SSujith 	/* Initialize regulatory */
852fb9987d0SSujith 	error = ath_regd_init(&common->regulatory, priv->hw->wiphy,
853fb9987d0SSujith 			      ath9k_reg_notifier);
854fb9987d0SSujith 	if (error)
855fb9987d0SSujith 		goto err_regd;
856fb9987d0SSujith 
857fb9987d0SSujith 	reg = &common->regulatory;
858fb9987d0SSujith 
859fb9987d0SSujith 	/* Setup TX */
860fb9987d0SSujith 	error = ath9k_tx_init(priv);
861fb9987d0SSujith 	if (error != 0)
862fb9987d0SSujith 		goto err_tx;
863fb9987d0SSujith 
864fb9987d0SSujith 	/* Setup RX */
865fb9987d0SSujith 	error = ath9k_rx_init(priv);
866fb9987d0SSujith 	if (error != 0)
867fb9987d0SSujith 		goto err_rx;
868fb9987d0SSujith 
869dc2a87f5SOleksij Rempel 	ath9k_hw_disable(priv->ah);
870d244f21eSSujith Manoharan #ifdef CONFIG_MAC80211_LEDS
871d244f21eSSujith Manoharan 	/* must be initialized before ieee80211_register_hw */
872d244f21eSSujith Manoharan 	priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw,
873d244f21eSSujith Manoharan 		IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_htc_tpt_blink,
874d244f21eSSujith Manoharan 		ARRAY_SIZE(ath9k_htc_tpt_blink));
875d244f21eSSujith Manoharan #endif
876d244f21eSSujith Manoharan 
877fb9987d0SSujith 	/* Register with mac80211 */
878fb9987d0SSujith 	error = ieee80211_register_hw(hw);
879fb9987d0SSujith 	if (error)
880fb9987d0SSujith 		goto err_register;
881fb9987d0SSujith 
882fb9987d0SSujith 	/* Handle world regulatory */
883fb9987d0SSujith 	if (!ath_is_world_regd(reg)) {
884fb9987d0SSujith 		error = regulatory_hint(hw->wiphy, reg->alpha2);
885fb9987d0SSujith 		if (error)
886fb9987d0SSujith 			goto err_world;
887fb9987d0SSujith 	}
888fb9987d0SSujith 
889e5facc75SRajkumar Manoharan 	error = ath9k_htc_init_debug(priv->ah);
890e5facc75SRajkumar Manoharan 	if (error) {
891e5facc75SRajkumar Manoharan 		ath_err(common, "Unable to create debugfs files\n");
892e5facc75SRajkumar Manoharan 		goto err_world;
893e5facc75SRajkumar Manoharan 	}
894e5facc75SRajkumar Manoharan 
895d2182b69SJoe Perches 	ath_dbg(common, CONFIG,
896d2182b69SJoe Perches 		"WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, BE:%d, BK:%d, VI:%d, VO:%d\n",
8973e3f1d19SSujith Manoharan 		priv->wmi_cmd_ep,
8983e3f1d19SSujith Manoharan 		priv->beacon_ep,
8993e3f1d19SSujith Manoharan 		priv->cab_ep,
9003e3f1d19SSujith Manoharan 		priv->uapsd_ep,
9013e3f1d19SSujith Manoharan 		priv->mgmt_ep,
9023e3f1d19SSujith Manoharan 		priv->data_be_ep,
9033e3f1d19SSujith Manoharan 		priv->data_bk_ep,
9043e3f1d19SSujith Manoharan 		priv->data_vi_ep,
9053e3f1d19SSujith Manoharan 		priv->data_vo_ep);
9063e3f1d19SSujith Manoharan 
9073e3f1d19SSujith Manoharan 	ath9k_hw_name(priv->ah, hw_name, sizeof(hw_name));
9083e3f1d19SSujith Manoharan 	wiphy_info(hw->wiphy, "%s\n", hw_name);
9093e3f1d19SSujith Manoharan 
910fb9987d0SSujith 	ath9k_init_leds(priv);
911fb9987d0SSujith 	ath9k_start_rfkill_poll(priv);
912fb9987d0SSujith 
913fb9987d0SSujith 	return 0;
914fb9987d0SSujith 
915fb9987d0SSujith err_world:
916fb9987d0SSujith 	ieee80211_unregister_hw(hw);
917fb9987d0SSujith err_register:
918fb9987d0SSujith 	ath9k_rx_cleanup(priv);
919fb9987d0SSujith err_rx:
920fb9987d0SSujith 	ath9k_tx_cleanup(priv);
921fb9987d0SSujith err_tx:
922fb9987d0SSujith 	/* Nothing */
923fb9987d0SSujith err_regd:
92429bbfb24SSujith Manoharan 	/* Nothing */
92529bbfb24SSujith Manoharan err_fw:
926fb9987d0SSujith 	ath9k_deinit_priv(priv);
927fb9987d0SSujith err_init:
928fb9987d0SSujith 	return error;
929fb9987d0SSujith }
930fb9987d0SSujith 
931fb9987d0SSujith int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
932fa6e15e0SRajkumar Manoharan 			   u16 devid, char *product, u32 drv_info)
933fb9987d0SSujith {
934fb9987d0SSujith 	struct ieee80211_hw *hw;
935fb9987d0SSujith 	struct ath9k_htc_priv *priv;
936fb9987d0SSujith 	int ret;
937fb9987d0SSujith 
938fb9987d0SSujith 	hw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), &ath9k_htc_ops);
939fb9987d0SSujith 	if (!hw)
940fb9987d0SSujith 		return -ENOMEM;
941fb9987d0SSujith 
942fb9987d0SSujith 	priv = hw->priv;
943fb9987d0SSujith 	priv->hw = hw;
944fb9987d0SSujith 	priv->htc = htc_handle;
945fb9987d0SSujith 	priv->dev = dev;
946fb9987d0SSujith 	htc_handle->drv_priv = priv;
947fb9987d0SSujith 	SET_IEEE80211_DEV(hw, priv->dev);
948fb9987d0SSujith 
949fb9987d0SSujith 	ret = ath9k_htc_wait_for_target(priv);
950fb9987d0SSujith 	if (ret)
951fb9987d0SSujith 		goto err_free;
952fb9987d0SSujith 
953fb9987d0SSujith 	priv->wmi = ath9k_init_wmi(priv);
954fb9987d0SSujith 	if (!priv->wmi) {
955fb9987d0SSujith 		ret = -EINVAL;
956fb9987d0SSujith 		goto err_free;
957fb9987d0SSujith 	}
958fb9987d0SSujith 
959fa6e15e0SRajkumar Manoharan 	ret = ath9k_init_htc_services(priv, devid, drv_info);
960fb9987d0SSujith 	if (ret)
961fb9987d0SSujith 		goto err_init;
962fb9987d0SSujith 
963fa6e15e0SRajkumar Manoharan 	ret = ath9k_init_device(priv, devid, product, drv_info);
964fb9987d0SSujith 	if (ret)
965fb9987d0SSujith 		goto err_init;
966fb9987d0SSujith 
967fb9987d0SSujith 	return 0;
968fb9987d0SSujith 
969fb9987d0SSujith err_init:
970fb9987d0SSujith 	ath9k_deinit_wmi(priv);
971fb9987d0SSujith err_free:
972fb9987d0SSujith 	ieee80211_free_hw(hw);
973fb9987d0SSujith 	return ret;
974fb9987d0SSujith }
975fb9987d0SSujith 
976fb9987d0SSujith void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug)
977fb9987d0SSujith {
978fb9987d0SSujith 	if (htc_handle->drv_priv) {
979a3be14b7SSujith 
980a3be14b7SSujith 		/* Check if the device has been yanked out. */
981a3be14b7SSujith 		if (hotunplug)
98297dcec57SSujith Manoharan 			htc_handle->drv_priv->ah->ah_flags |= AH_UNPLUGGED;
983a3be14b7SSujith 
984fb9987d0SSujith 		ath9k_deinit_device(htc_handle->drv_priv);
985fb9987d0SSujith 		ath9k_deinit_wmi(htc_handle->drv_priv);
986fb9987d0SSujith 		ieee80211_free_hw(htc_handle->drv_priv->hw);
987fb9987d0SSujith 	}
988fb9987d0SSujith }
989fb9987d0SSujith 
990fb9987d0SSujith #ifdef CONFIG_PM
991f933ebedSSujith Manoharan 
992f933ebedSSujith Manoharan void ath9k_htc_suspend(struct htc_target *htc_handle)
993f933ebedSSujith Manoharan {
994f933ebedSSujith Manoharan 	ath9k_htc_setpower(htc_handle->drv_priv, ATH9K_PM_FULL_SLEEP);
995f933ebedSSujith Manoharan }
996f933ebedSSujith Manoharan 
997fb9987d0SSujith int ath9k_htc_resume(struct htc_target *htc_handle)
998fb9987d0SSujith {
999fa6e15e0SRajkumar Manoharan 	struct ath9k_htc_priv *priv = htc_handle->drv_priv;
1000fb9987d0SSujith 	int ret;
1001fb9987d0SSujith 
1002fa6e15e0SRajkumar Manoharan 	ret = ath9k_htc_wait_for_target(priv);
1003fb9987d0SSujith 	if (ret)
1004fb9987d0SSujith 		return ret;
1005fb9987d0SSujith 
1006fa6e15e0SRajkumar Manoharan 	ret = ath9k_init_htc_services(priv, priv->ah->hw_version.devid,
10070b5ead91SSujith Manoharan 				      priv->ah->hw_version.usbdev);
10081e51acaaSOleksij Rempel 	ath9k_configure_leds(priv);
10091e51acaaSOleksij Rempel 
1010fb9987d0SSujith 	return ret;
1011fb9987d0SSujith }
1012fb9987d0SSujith #endif
1013fb9987d0SSujith 
1014fb9987d0SSujith static int __init ath9k_htc_init(void)
1015fb9987d0SSujith {
1016e5facc75SRajkumar Manoharan 	if (ath9k_hif_usb_init() < 0) {
1017516304b0SJoe Perches 		pr_err("No USB devices found, driver not installed\n");
1018e5facc75SRajkumar Manoharan 		return -ENODEV;
1019fb9987d0SSujith 	}
1020fb9987d0SSujith 
1021fb9987d0SSujith 	return 0;
1022fb9987d0SSujith }
1023fb9987d0SSujith module_init(ath9k_htc_init);
1024fb9987d0SSujith 
1025fb9987d0SSujith static void __exit ath9k_htc_exit(void)
1026fb9987d0SSujith {
1027fb9987d0SSujith 	ath9k_hif_usb_exit();
1028516304b0SJoe Perches 	pr_info("Driver unloaded\n");
1029fb9987d0SSujith }
1030fb9987d0SSujith module_exit(ath9k_htc_exit);
1031