htc_drv_init.c revision 4e63f768c3b85ae2b3ea6251231fd5cc46ec598d
1fb9987d0f748c983bb795a86f47522313f701a08Sujith/*
2fb9987d0f748c983bb795a86f47522313f701a08Sujith * Copyright (c) 2010 Atheros Communications Inc.
3fb9987d0f748c983bb795a86f47522313f701a08Sujith *
4fb9987d0f748c983bb795a86f47522313f701a08Sujith * Permission to use, copy, modify, and/or distribute this software for any
5fb9987d0f748c983bb795a86f47522313f701a08Sujith * purpose with or without fee is hereby granted, provided that the above
6fb9987d0f748c983bb795a86f47522313f701a08Sujith * copyright notice and this permission notice appear in all copies.
7fb9987d0f748c983bb795a86f47522313f701a08Sujith *
8fb9987d0f748c983bb795a86f47522313f701a08Sujith * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9fb9987d0f748c983bb795a86f47522313f701a08Sujith * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10fb9987d0f748c983bb795a86f47522313f701a08Sujith * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11fb9987d0f748c983bb795a86f47522313f701a08Sujith * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12fb9987d0f748c983bb795a86f47522313f701a08Sujith * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13fb9987d0f748c983bb795a86f47522313f701a08Sujith * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14fb9987d0f748c983bb795a86f47522313f701a08Sujith * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15fb9987d0f748c983bb795a86f47522313f701a08Sujith */
16fb9987d0f748c983bb795a86f47522313f701a08Sujith
17fb9987d0f748c983bb795a86f47522313f701a08Sujith#include "htc.h"
18fb9987d0f748c983bb795a86f47522313f701a08Sujith
19fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_AUTHOR("Atheros Communications");
20fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_LICENSE("Dual BSD/GPL");
21fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_DESCRIPTION("Atheros driver 802.11n HTC based wireless devices");
22fb9987d0f748c983bb795a86f47522313f701a08Sujith
23fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic unsigned int ath9k_debug = ATH_DBG_DEFAULT;
24fb9987d0f748c983bb795a86f47522313f701a08Sujithmodule_param_named(debug, ath9k_debug, uint, 0);
25fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_PARM_DESC(debug, "Debugging mask");
26fb9987d0f748c983bb795a86f47522313f701a08Sujith
27e1572c5eeca8ef87a250322364584458b2dadb35Sujithint htc_modparam_nohwcrypt;
28e1572c5eeca8ef87a250322364584458b2dadb35Sujithmodule_param_named(nohwcrypt, htc_modparam_nohwcrypt, int, 0444);
29fb9987d0f748c983bb795a86f47522313f701a08SujithMODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
30fb9987d0f748c983bb795a86f47522313f701a08Sujith
31fb9987d0f748c983bb795a86f47522313f701a08Sujith#define CHAN2G(_freq, _idx)  { \
32fb9987d0f748c983bb795a86f47522313f701a08Sujith	.center_freq = (_freq), \
33fb9987d0f748c983bb795a86f47522313f701a08Sujith	.hw_value = (_idx), \
34fb9987d0f748c983bb795a86f47522313f701a08Sujith	.max_power = 20, \
35fb9987d0f748c983bb795a86f47522313f701a08Sujith}
36fb9987d0f748c983bb795a86f47522313f701a08Sujith
37ea46e644e80bd4ac778964afd998df4f666486d4Sujith#define CHAN5G(_freq, _idx) { \
38ea46e644e80bd4ac778964afd998df4f666486d4Sujith	.band = IEEE80211_BAND_5GHZ, \
39ea46e644e80bd4ac778964afd998df4f666486d4Sujith	.center_freq = (_freq), \
40ea46e644e80bd4ac778964afd998df4f666486d4Sujith	.hw_value = (_idx), \
41ea46e644e80bd4ac778964afd998df4f666486d4Sujith	.max_power = 20, \
42ea46e644e80bd4ac778964afd998df4f666486d4Sujith}
43ea46e644e80bd4ac778964afd998df4f666486d4Sujith
44fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic struct ieee80211_channel ath9k_2ghz_channels[] = {
45fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2412, 0), /* Channel 1 */
46fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2417, 1), /* Channel 2 */
47fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2422, 2), /* Channel 3 */
48fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2427, 3), /* Channel 4 */
49fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2432, 4), /* Channel 5 */
50fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2437, 5), /* Channel 6 */
51fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2442, 6), /* Channel 7 */
52fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2447, 7), /* Channel 8 */
53fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2452, 8), /* Channel 9 */
54fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2457, 9), /* Channel 10 */
55fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2462, 10), /* Channel 11 */
56fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2467, 11), /* Channel 12 */
57fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2472, 12), /* Channel 13 */
58fb9987d0f748c983bb795a86f47522313f701a08Sujith	CHAN2G(2484, 13), /* Channel 14 */
59fb9987d0f748c983bb795a86f47522313f701a08Sujith};
60fb9987d0f748c983bb795a86f47522313f701a08Sujith
61ea46e644e80bd4ac778964afd998df4f666486d4Sujithstatic struct ieee80211_channel ath9k_5ghz_channels[] = {
62ea46e644e80bd4ac778964afd998df4f666486d4Sujith	/* _We_ call this UNII 1 */
63ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5180, 14), /* Channel 36 */
64ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5200, 15), /* Channel 40 */
65ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5220, 16), /* Channel 44 */
66ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5240, 17), /* Channel 48 */
67ea46e644e80bd4ac778964afd998df4f666486d4Sujith	/* _We_ call this UNII 2 */
68ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5260, 18), /* Channel 52 */
69ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5280, 19), /* Channel 56 */
70ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5300, 20), /* Channel 60 */
71ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5320, 21), /* Channel 64 */
72ea46e644e80bd4ac778964afd998df4f666486d4Sujith	/* _We_ call this "Middle band" */
73ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5500, 22), /* Channel 100 */
74ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5520, 23), /* Channel 104 */
75ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5540, 24), /* Channel 108 */
76ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5560, 25), /* Channel 112 */
77ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5580, 26), /* Channel 116 */
78ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5600, 27), /* Channel 120 */
79ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5620, 28), /* Channel 124 */
80ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5640, 29), /* Channel 128 */
81ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5660, 30), /* Channel 132 */
82ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5680, 31), /* Channel 136 */
83ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5700, 32), /* Channel 140 */
84ea46e644e80bd4ac778964afd998df4f666486d4Sujith	/* _We_ call this UNII 3 */
85ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5745, 33), /* Channel 149 */
86ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5765, 34), /* Channel 153 */
87ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5785, 35), /* Channel 157 */
88ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5805, 36), /* Channel 161 */
89ea46e644e80bd4ac778964afd998df4f666486d4Sujith	CHAN5G(5825, 37), /* Channel 165 */
90ea46e644e80bd4ac778964afd998df4f666486d4Sujith};
91ea46e644e80bd4ac778964afd998df4f666486d4Sujith
92fb9987d0f748c983bb795a86f47522313f701a08Sujith/* Atheros hardware rate code addition for short premble */
93fb9987d0f748c983bb795a86f47522313f701a08Sujith#define SHPCHECK(__hw_rate, __flags) \
94fb9987d0f748c983bb795a86f47522313f701a08Sujith	((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0)
95fb9987d0f748c983bb795a86f47522313f701a08Sujith
96fb9987d0f748c983bb795a86f47522313f701a08Sujith#define RATE(_bitrate, _hw_rate, _flags) {		\
97fb9987d0f748c983bb795a86f47522313f701a08Sujith	.bitrate	= (_bitrate),			\
98fb9987d0f748c983bb795a86f47522313f701a08Sujith	.flags		= (_flags),			\
99fb9987d0f748c983bb795a86f47522313f701a08Sujith	.hw_value	= (_hw_rate),			\
100fb9987d0f748c983bb795a86f47522313f701a08Sujith	.hw_value_short = (SHPCHECK(_hw_rate, _flags))	\
101fb9987d0f748c983bb795a86f47522313f701a08Sujith}
102fb9987d0f748c983bb795a86f47522313f701a08Sujith
103fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic struct ieee80211_rate ath9k_legacy_rates[] = {
104fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(10, 0x1b, 0),
105fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */
106fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */
107fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */
108fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(60, 0x0b, 0),
109fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(90, 0x0f, 0),
110fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(120, 0x0a, 0),
111fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(180, 0x0e, 0),
112fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(240, 0x09, 0),
113fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(360, 0x0d, 0),
114fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(480, 0x08, 0),
115fb9987d0f748c983bb795a86f47522313f701a08Sujith	RATE(540, 0x0c, 0),
116fb9987d0f748c983bb795a86f47522313f701a08Sujith};
117fb9987d0f748c983bb795a86f47522313f701a08Sujith
118fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
119fb9987d0f748c983bb795a86f47522313f701a08Sujith{
120fb9987d0f748c983bb795a86f47522313f701a08Sujith	int time_left;
121fb9987d0f748c983bb795a86f47522313f701a08Sujith
122d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com	if (atomic_read(&priv->htc->tgt_ready) > 0) {
123d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com		atomic_dec(&priv->htc->tgt_ready);
124d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com		return 0;
125d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com	}
126d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com
127fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Firmware can take up to 50ms to get ready, to be safe use 1 second */
128fb9987d0f748c983bb795a86f47522313f701a08Sujith	time_left = wait_for_completion_timeout(&priv->htc->target_wait, HZ);
129fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!time_left) {
130fb9987d0f748c983bb795a86f47522313f701a08Sujith		dev_err(priv->dev, "ath9k_htc: Target is unresponsive\n");
131fb9987d0f748c983bb795a86f47522313f701a08Sujith		return -ETIMEDOUT;
132fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
133fb9987d0f748c983bb795a86f47522313f701a08Sujith
134d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com	atomic_dec(&priv->htc->tgt_ready);
135d8c49ffb2e2a47b23fec7f469435e7b112e2e569Sujith.Manoharan@atheros.com
136fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
137fb9987d0f748c983bb795a86f47522313f701a08Sujith}
138fb9987d0f748c983bb795a86f47522313f701a08Sujith
139fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
140fb9987d0f748c983bb795a86f47522313f701a08Sujith{
141e1572c5eeca8ef87a250322364584458b2dadb35Sujith	ath9k_htc_exit_debug(priv->ah);
142fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_deinit(priv->ah);
143fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_kill(&priv->wmi_tasklet);
144fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_kill(&priv->rx_tasklet);
145fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_kill(&priv->tx_tasklet);
146fb9987d0f748c983bb795a86f47522313f701a08Sujith	kfree(priv->ah);
147fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->ah = NULL;
148fb9987d0f748c983bb795a86f47522313f701a08Sujith}
149fb9987d0f748c983bb795a86f47522313f701a08Sujith
150fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_deinit_device(struct ath9k_htc_priv *priv)
151fb9987d0f748c983bb795a86f47522313f701a08Sujith{
152fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw = priv->hw;
153fb9987d0f748c983bb795a86f47522313f701a08Sujith
154fb9987d0f748c983bb795a86f47522313f701a08Sujith	wiphy_rfkill_stop_polling(hw->wiphy);
155fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_deinit_leds(priv);
156fb9987d0f748c983bb795a86f47522313f701a08Sujith	ieee80211_unregister_hw(hw);
157fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_rx_cleanup(priv);
158fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_tx_cleanup(priv);
159fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_deinit_priv(priv);
160fb9987d0f748c983bb795a86f47522313f701a08Sujith}
161fb9987d0f748c983bb795a86f47522313f701a08Sujith
162fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic inline int ath9k_htc_connect_svc(struct ath9k_htc_priv *priv,
163fb9987d0f748c983bb795a86f47522313f701a08Sujith					u16 service_id,
164fb9987d0f748c983bb795a86f47522313f701a08Sujith					void (*tx) (void *,
165fb9987d0f748c983bb795a86f47522313f701a08Sujith						    struct sk_buff *,
166fb9987d0f748c983bb795a86f47522313f701a08Sujith						    enum htc_endpoint_id,
167fb9987d0f748c983bb795a86f47522313f701a08Sujith						    bool txok),
168fb9987d0f748c983bb795a86f47522313f701a08Sujith					enum htc_endpoint_id *ep_id)
169fb9987d0f748c983bb795a86f47522313f701a08Sujith{
170fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct htc_service_connreq req;
171fb9987d0f748c983bb795a86f47522313f701a08Sujith
172fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(&req, 0, sizeof(struct htc_service_connreq));
173fb9987d0f748c983bb795a86f47522313f701a08Sujith
174fb9987d0f748c983bb795a86f47522313f701a08Sujith	req.service_id = service_id;
175fb9987d0f748c983bb795a86f47522313f701a08Sujith	req.ep_callbacks.priv = priv;
176fb9987d0f748c983bb795a86f47522313f701a08Sujith	req.ep_callbacks.rx = ath9k_htc_rxep;
177fb9987d0f748c983bb795a86f47522313f701a08Sujith	req.ep_callbacks.tx = tx;
178fb9987d0f748c983bb795a86f47522313f701a08Sujith
179fb9987d0f748c983bb795a86f47522313f701a08Sujith	return htc_connect_service(priv->htc, &req, ep_id);
180fb9987d0f748c983bb795a86f47522313f701a08Sujith}
181fb9987d0f748c983bb795a86f47522313f701a08Sujith
1826267dc709c6ef1c0926e18ff2859238992dea658Sujithstatic int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid)
183fb9987d0f748c983bb795a86f47522313f701a08Sujith{
184fb9987d0f748c983bb795a86f47522313f701a08Sujith	int ret;
185fb9987d0f748c983bb795a86f47522313f701a08Sujith
186fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* WMI CMD*/
187fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_wmi_connect(priv->htc, priv->wmi, &priv->wmi_cmd_ep);
188fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
189fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
190fb9987d0f748c983bb795a86f47522313f701a08Sujith
191fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Beacon */
1929c6dda4e2dfea970a7105e3805f0195bc3079f2fSujith	ret = ath9k_htc_connect_svc(priv, WMI_BEACON_SVC, ath9k_htc_beaconep,
193fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->beacon_ep);
194fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
195fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
196fb9987d0f748c983bb795a86f47522313f701a08Sujith
197fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* CAB */
198fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_CAB_SVC, ath9k_htc_txep,
199fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->cab_ep);
200fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
201fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
202fb9987d0f748c983bb795a86f47522313f701a08Sujith
203fb9987d0f748c983bb795a86f47522313f701a08Sujith
204fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* UAPSD */
205fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_UAPSD_SVC, ath9k_htc_txep,
206fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->uapsd_ep);
207fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
208fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
209fb9987d0f748c983bb795a86f47522313f701a08Sujith
210fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* MGMT */
211fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_MGMT_SVC, ath9k_htc_txep,
212fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->mgmt_ep);
213fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
214fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
215fb9987d0f748c983bb795a86f47522313f701a08Sujith
216fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* DATA BE */
217fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_DATA_BE_SVC, ath9k_htc_txep,
218fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->data_be_ep);
219fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
220fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
221fb9987d0f748c983bb795a86f47522313f701a08Sujith
222fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* DATA BK */
223fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_DATA_BK_SVC, ath9k_htc_txep,
224fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->data_bk_ep);
225fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
226fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
227fb9987d0f748c983bb795a86f47522313f701a08Sujith
228fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* DATA VI */
229fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_DATA_VI_SVC, ath9k_htc_txep,
230fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->data_vi_ep);
231fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
232fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
233fb9987d0f748c983bb795a86f47522313f701a08Sujith
234fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* DATA VO */
235fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_connect_svc(priv, WMI_DATA_VO_SVC, ath9k_htc_txep,
236fb9987d0f748c983bb795a86f47522313f701a08Sujith				    &priv->data_vo_ep);
237fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
238fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
239fb9987d0f748c983bb795a86f47522313f701a08Sujith
2406267dc709c6ef1c0926e18ff2859238992dea658Sujith	/*
2416267dc709c6ef1c0926e18ff2859238992dea658Sujith	 * Setup required credits before initializing HTC.
2426267dc709c6ef1c0926e18ff2859238992dea658Sujith	 * This is a bit hacky, but, since queuing is done in
2436267dc709c6ef1c0926e18ff2859238992dea658Sujith	 * the HIF layer, shouldn't matter much.
2446267dc709c6ef1c0926e18ff2859238992dea658Sujith	 */
2456267dc709c6ef1c0926e18ff2859238992dea658Sujith
2466267dc709c6ef1c0926e18ff2859238992dea658Sujith	switch(devid) {
2476267dc709c6ef1c0926e18ff2859238992dea658Sujith	case 0x7010:
2484e63f768c3b85ae2b3ea6251231fd5cc46ec598dSujith	case 0x9018:
2496267dc709c6ef1c0926e18ff2859238992dea658Sujith		priv->htc->credits = 45;
2506267dc709c6ef1c0926e18ff2859238992dea658Sujith		break;
2516267dc709c6ef1c0926e18ff2859238992dea658Sujith	default:
2524e63f768c3b85ae2b3ea6251231fd5cc46ec598dSujith		priv->htc->credits = 33;
2536267dc709c6ef1c0926e18ff2859238992dea658Sujith	}
2546267dc709c6ef1c0926e18ff2859238992dea658Sujith
255fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = htc_init(priv->htc);
256fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
257fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
258fb9987d0f748c983bb795a86f47522313f701a08Sujith
2596267dc709c6ef1c0926e18ff2859238992dea658Sujith	dev_info(priv->dev, "ath9k_htc: HTC initialized with %d credits\n",
2606267dc709c6ef1c0926e18ff2859238992dea658Sujith		 priv->htc->credits);
2616267dc709c6ef1c0926e18ff2859238992dea658Sujith
262fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
263fb9987d0f748c983bb795a86f47522313f701a08Sujith
264fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
265fb9987d0f748c983bb795a86f47522313f701a08Sujith	dev_err(priv->dev, "ath9k_htc: Unable to initialize HTC services\n");
266fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ret;
267fb9987d0f748c983bb795a86f47522313f701a08Sujith}
268fb9987d0f748c983bb795a86f47522313f701a08Sujith
269fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_reg_notifier(struct wiphy *wiphy,
270fb9987d0f748c983bb795a86f47522313f701a08Sujith			      struct regulatory_request *request)
271fb9987d0f748c983bb795a86f47522313f701a08Sujith{
272fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
273fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = hw->priv;
274fb9987d0f748c983bb795a86f47522313f701a08Sujith
275fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ath_reg_notifier_apply(wiphy, request,
276fb9987d0f748c983bb795a86f47522313f701a08Sujith				      ath9k_hw_regulatory(priv->ah));
277fb9987d0f748c983bb795a86f47522313f701a08Sujith}
278fb9987d0f748c983bb795a86f47522313f701a08Sujith
2794a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
280fb9987d0f748c983bb795a86f47522313f701a08Sujith{
281fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
282fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
283fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
284fb9987d0f748c983bb795a86f47522313f701a08Sujith	__be32 val, reg = cpu_to_be32(reg_offset);
285fb9987d0f748c983bb795a86f47522313f701a08Sujith	int r;
286fb9987d0f748c983bb795a86f47522313f701a08Sujith
287fb9987d0f748c983bb795a86f47522313f701a08Sujith	r = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID,
288fb9987d0f748c983bb795a86f47522313f701a08Sujith			  (u8 *) &reg, sizeof(reg),
289fb9987d0f748c983bb795a86f47522313f701a08Sujith			  (u8 *) &val, sizeof(val),
290fb9987d0f748c983bb795a86f47522313f701a08Sujith			  100);
291fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (unlikely(r)) {
292fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_WMI,
293fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "REGISTER READ FAILED: (0x%04x, %d)\n",
294fb9987d0f748c983bb795a86f47522313f701a08Sujith			   reg_offset, r);
295fb9987d0f748c983bb795a86f47522313f701a08Sujith		return -EIO;
296fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
297fb9987d0f748c983bb795a86f47522313f701a08Sujith
298fb9987d0f748c983bb795a86f47522313f701a08Sujith	return be32_to_cpu(val);
299fb9987d0f748c983bb795a86f47522313f701a08Sujith}
300fb9987d0f748c983bb795a86f47522313f701a08Sujith
3014a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
302fb9987d0f748c983bb795a86f47522313f701a08Sujith{
303fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
304fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(ah);
305fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
306fb9987d0f748c983bb795a86f47522313f701a08Sujith	__be32 buf[2] = {
307fb9987d0f748c983bb795a86f47522313f701a08Sujith		cpu_to_be32(reg_offset),
308fb9987d0f748c983bb795a86f47522313f701a08Sujith		cpu_to_be32(val),
309fb9987d0f748c983bb795a86f47522313f701a08Sujith	};
310fb9987d0f748c983bb795a86f47522313f701a08Sujith	int r;
311fb9987d0f748c983bb795a86f47522313f701a08Sujith
312fb9987d0f748c983bb795a86f47522313f701a08Sujith	r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
313fb9987d0f748c983bb795a86f47522313f701a08Sujith			  (u8 *) &buf, sizeof(buf),
314fb9987d0f748c983bb795a86f47522313f701a08Sujith			  (u8 *) &val, sizeof(val),
315fb9987d0f748c983bb795a86f47522313f701a08Sujith			  100);
316fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (unlikely(r)) {
317fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_WMI,
318fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "REGISTER WRITE FAILED:(0x%04x, %d)\n",
319fb9987d0f748c983bb795a86f47522313f701a08Sujith			  reg_offset, r);
320fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
321fb9987d0f748c983bb795a86f47522313f701a08Sujith}
322fb9987d0f748c983bb795a86f47522313f701a08Sujith
3234a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
3244a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{
3254a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
3264a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_common *common = ath9k_hw_common(ah);
3274a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
3284a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	u32 rsp_status;
3294a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	int r;
3304a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3314a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	mutex_lock(&priv->wmi->multi_write_mutex);
3324a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3334a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	/* Store the register/value */
3344a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	priv->wmi->multi_write[priv->wmi->multi_write_idx].reg =
3354a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		cpu_to_be32(reg_offset);
3364a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	priv->wmi->multi_write[priv->wmi->multi_write_idx].val =
3374a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		cpu_to_be32(val);
3384a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3394a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	priv->wmi->multi_write_idx++;
3404a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3414a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	/* If the buffer is full, send it out. */
3424a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) {
3434a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
3444a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  (u8 *) &priv->wmi->multi_write,
3454a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  sizeof(struct register_write) * priv->wmi->multi_write_idx,
3464a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  (u8 *) &rsp_status, sizeof(rsp_status),
3474a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  100);
3484a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		if (unlikely(r)) {
3494a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			ath_print(common, ATH_DBG_WMI,
3504a22fe108e62367c10c3abeb469d6972ba3299f5Sujith				  "REGISTER WRITE FAILED, multi len: %d\n",
3514a22fe108e62367c10c3abeb469d6972ba3299f5Sujith				  priv->wmi->multi_write_idx);
3524a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		}
3534a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		priv->wmi->multi_write_idx = 0;
3544a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	}
3554a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3564a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	mutex_unlock(&priv->wmi->multi_write_mutex);
3574a22fe108e62367c10c3abeb469d6972ba3299f5Sujith}
3584a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3594a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset)
3604a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{
3614a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
3624a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_common *common = ath9k_hw_common(ah);
3634a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
3644a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3654a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	if (atomic_read(&priv->wmi->mwrite_cnt))
3664a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		ath9k_regwrite_buffer(hw_priv, val, reg_offset);
3674a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	else
3684a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		ath9k_regwrite_single(hw_priv, val, reg_offset);
3694a22fe108e62367c10c3abeb469d6972ba3299f5Sujith}
3704a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3714a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_enable_regwrite_buffer(void *hw_priv)
3724a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{
3734a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
3744a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_common *common = ath9k_hw_common(ah);
3754a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
3764a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3774a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	atomic_inc(&priv->wmi->mwrite_cnt);
3784a22fe108e62367c10c3abeb469d6972ba3299f5Sujith}
3794a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3804a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_disable_regwrite_buffer(void *hw_priv)
3814a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{
3824a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
3834a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_common *common = ath9k_hw_common(ah);
3844a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
3854a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3864a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	atomic_dec(&priv->wmi->mwrite_cnt);
3874a22fe108e62367c10c3abeb469d6972ba3299f5Sujith}
3884a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3894a22fe108e62367c10c3abeb469d6972ba3299f5Sujithstatic void ath9k_regwrite_flush(void *hw_priv)
3904a22fe108e62367c10c3abeb469d6972ba3299f5Sujith{
3914a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_hw *ah = (struct ath_hw *) hw_priv;
3924a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath_common *common = ath9k_hw_common(ah);
3934a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
3944a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	u32 rsp_status;
3954a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	int r;
3964a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3974a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	mutex_lock(&priv->wmi->multi_write_mutex);
3984a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
3994a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	if (priv->wmi->multi_write_idx) {
4004a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
4014a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  (u8 *) &priv->wmi->multi_write,
4024a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  sizeof(struct register_write) * priv->wmi->multi_write_idx,
4034a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  (u8 *) &rsp_status, sizeof(rsp_status),
4044a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			  100);
4054a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		if (unlikely(r)) {
4064a22fe108e62367c10c3abeb469d6972ba3299f5Sujith			ath_print(common, ATH_DBG_WMI,
4074a22fe108e62367c10c3abeb469d6972ba3299f5Sujith				  "REGISTER WRITE FAILED, multi len: %d\n",
4084a22fe108e62367c10c3abeb469d6972ba3299f5Sujith				  priv->wmi->multi_write_idx);
4094a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		}
4104a22fe108e62367c10c3abeb469d6972ba3299f5Sujith		priv->wmi->multi_write_idx = 0;
4114a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	}
4124a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
4134a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	mutex_unlock(&priv->wmi->multi_write_mutex);
4144a22fe108e62367c10c3abeb469d6972ba3299f5Sujith}
4154a22fe108e62367c10c3abeb469d6972ba3299f5Sujith
416fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic const struct ath_ops ath9k_common_ops = {
4174a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	.read = ath9k_regread,
4184a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	.write = ath9k_regwrite,
4194a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	.enable_write_buffer = ath9k_enable_regwrite_buffer,
4204a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	.disable_write_buffer = ath9k_disable_regwrite_buffer,
4214a22fe108e62367c10c3abeb469d6972ba3299f5Sujith	.write_flush = ath9k_regwrite_flush,
422fb9987d0f748c983bb795a86f47522313f701a08Sujith};
423fb9987d0f748c983bb795a86f47522313f701a08Sujith
424fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath_usb_read_cachesize(struct ath_common *common, int *csz)
425fb9987d0f748c983bb795a86f47522313f701a08Sujith{
426fb9987d0f748c983bb795a86f47522313f701a08Sujith	*csz = L1_CACHE_BYTES >> 2;
427fb9987d0f748c983bb795a86f47522313f701a08Sujith}
428fb9987d0f748c983bb795a86f47522313f701a08Sujith
429fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
430fb9987d0f748c983bb795a86f47522313f701a08Sujith{
431fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = (struct ath_hw *) common->ah;
432fb9987d0f748c983bb795a86f47522313f701a08Sujith
433fb9987d0f748c983bb795a86f47522313f701a08Sujith	(void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
434fb9987d0f748c983bb795a86f47522313f701a08Sujith
435fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!ath9k_hw_wait(ah,
436fb9987d0f748c983bb795a86f47522313f701a08Sujith			   AR_EEPROM_STATUS_DATA,
437fb9987d0f748c983bb795a86f47522313f701a08Sujith			   AR_EEPROM_STATUS_DATA_BUSY |
438fb9987d0f748c983bb795a86f47522313f701a08Sujith			   AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
439fb9987d0f748c983bb795a86f47522313f701a08Sujith			   AH_WAIT_TIMEOUT))
440fb9987d0f748c983bb795a86f47522313f701a08Sujith		return false;
441fb9987d0f748c983bb795a86f47522313f701a08Sujith
442fb9987d0f748c983bb795a86f47522313f701a08Sujith	*data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
443fb9987d0f748c983bb795a86f47522313f701a08Sujith		   AR_EEPROM_STATUS_DATA_VAL);
444fb9987d0f748c983bb795a86f47522313f701a08Sujith
445fb9987d0f748c983bb795a86f47522313f701a08Sujith	return true;
446fb9987d0f748c983bb795a86f47522313f701a08Sujith}
447fb9987d0f748c983bb795a86f47522313f701a08Sujith
448fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic const struct ath_bus_ops ath9k_usb_bus_ops = {
449497ad9adf44013dc9054f80c627acc44d4c90d37Sujith	.ath_bus_type = ATH_USB,
450fb9987d0f748c983bb795a86f47522313f701a08Sujith	.read_cachesize = ath_usb_read_cachesize,
451fb9987d0f748c983bb795a86f47522313f701a08Sujith	.eeprom_read = ath_usb_eeprom_read,
452fb9987d0f748c983bb795a86f47522313f701a08Sujith};
453fb9987d0f748c983bb795a86f47522313f701a08Sujith
454fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void setup_ht_cap(struct ath9k_htc_priv *priv,
455fb9987d0f748c983bb795a86f47522313f701a08Sujith			 struct ieee80211_sta_ht_cap *ht_info)
456fb9987d0f748c983bb795a86f47522313f701a08Sujith{
4576debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
4586debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	u8 tx_streams, rx_streams;
4596debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	int i;
4606debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
461fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->ht_supported = true;
462fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
463fb9987d0f748c983bb795a86f47522313f701a08Sujith		       IEEE80211_HT_CAP_SM_PS |
464fb9987d0f748c983bb795a86f47522313f701a08Sujith		       IEEE80211_HT_CAP_SGI_40 |
465fb9987d0f748c983bb795a86f47522313f701a08Sujith		       IEEE80211_HT_CAP_DSSSCCK40;
466fb9987d0f748c983bb795a86f47522313f701a08Sujith
467b4dec5e8f5c02f75d8c08dd377193f73b553bfe2Sujith	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
468b4dec5e8f5c02f75d8c08dd377193f73b553bfe2Sujith		ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
469b4dec5e8f5c02f75d8c08dd377193f73b553bfe2Sujith
47017525f96aeeed156bd4a6dee21816100f77b0c71Sujith	ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
47117525f96aeeed156bd4a6dee21816100f77b0c71Sujith
472fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
473fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
474fb9987d0f748c983bb795a86f47522313f701a08Sujith
475fb9987d0f748c983bb795a86f47522313f701a08Sujith	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
4766debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
4776debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	/* ath9k_htc supports only 1 or 2 stream devices */
4786debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, 2);
4796debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, 2);
4806debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
4816debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	ath_print(common, ATH_DBG_CONFIG,
4826debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith		  "TX streams %d, RX streams: %d\n",
4836debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith		  tx_streams, rx_streams);
4846debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
4856debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	if (tx_streams != rx_streams) {
4866debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
4876debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith		ht_info->mcs.tx_params |= ((tx_streams - 1) <<
4886debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith					   IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
4896debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	}
4906debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
4916debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith	for (i = 0; i < rx_streams; i++)
4926debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith		ht_info->mcs.rx_mask[i] = 0xff;
4936debecad452d3bbe5affc0a21bc0bb452f867cd8Sujith
494fb9987d0f748c983bb795a86f47522313f701a08Sujith	ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
495fb9987d0f748c983bb795a86f47522313f701a08Sujith}
496fb9987d0f748c983bb795a86f47522313f701a08Sujith
497fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_init_queues(struct ath9k_htc_priv *priv)
498fb9987d0f748c983bb795a86f47522313f701a08Sujith{
499fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
500fb9987d0f748c983bb795a86f47522313f701a08Sujith	int i;
501fb9987d0f748c983bb795a86f47522313f701a08Sujith
502fb9987d0f748c983bb795a86f47522313f701a08Sujith	for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++)
503fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->hwq_map[i] = -1;
504fb9987d0f748c983bb795a86f47522313f701a08Sujith
505ca74b83b66dbd289a395c6243695d746c76676ccSujith	priv->beaconq = ath9k_hw_beaconq_setup(priv->ah);
506ca74b83b66dbd289a395c6243695d746c76676ccSujith	if (priv->beaconq == -1) {
507ca74b83b66dbd289a395c6243695d746c76676ccSujith		ath_print(common, ATH_DBG_FATAL,
508ca74b83b66dbd289a395c6243695d746c76676ccSujith			  "Unable to setup BEACON xmit queue\n");
509ca74b83b66dbd289a395c6243695d746c76676ccSujith		goto err;
510ca74b83b66dbd289a395c6243695d746c76676ccSujith	}
511ca74b83b66dbd289a395c6243695d746c76676ccSujith
512ca74b83b66dbd289a395c6243695d746c76676ccSujith	priv->cabq = ath9k_htc_cabq_setup(priv);
513ca74b83b66dbd289a395c6243695d746c76676ccSujith	if (priv->cabq == -1) {
514ca74b83b66dbd289a395c6243695d746c76676ccSujith		ath_print(common, ATH_DBG_FATAL,
515ca74b83b66dbd289a395c6243695d746c76676ccSujith			  "Unable to setup CAB xmit queue\n");
516ca74b83b66dbd289a395c6243695d746c76676ccSujith		goto err;
517ca74b83b66dbd289a395c6243695d746c76676ccSujith	}
518ca74b83b66dbd289a395c6243695d746c76676ccSujith
519e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau	if (!ath9k_htc_txq_setup(priv, WME_AC_BE)) {
520fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_FATAL,
521fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "Unable to setup xmit queue for BE traffic\n");
522fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
523fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
524fb9987d0f748c983bb795a86f47522313f701a08Sujith
525e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau	if (!ath9k_htc_txq_setup(priv, WME_AC_BK)) {
526fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_FATAL,
527fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "Unable to setup xmit queue for BK traffic\n");
528fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
529fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
530e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau	if (!ath9k_htc_txq_setup(priv, WME_AC_VI)) {
531fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_FATAL,
532fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "Unable to setup xmit queue for VI traffic\n");
533fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
534fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
535e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau	if (!ath9k_htc_txq_setup(priv, WME_AC_VO)) {
536fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_FATAL,
537fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "Unable to setup xmit queue for VO traffic\n");
538fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err;
539fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
540fb9987d0f748c983bb795a86f47522313f701a08Sujith
541fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
542fb9987d0f748c983bb795a86f47522313f701a08Sujith
543fb9987d0f748c983bb795a86f47522313f701a08Sujitherr:
544fb9987d0f748c983bb795a86f47522313f701a08Sujith	return -EINVAL;
545fb9987d0f748c983bb795a86f47522313f701a08Sujith}
546fb9987d0f748c983bb795a86f47522313f701a08Sujith
547fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_init_crypto(struct ath9k_htc_priv *priv)
548fb9987d0f748c983bb795a86f47522313f701a08Sujith{
549fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
550fb9987d0f748c983bb795a86f47522313f701a08Sujith	int i = 0;
551fb9987d0f748c983bb795a86f47522313f701a08Sujith
552fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Get the hardware key cache size. */
553fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->keymax = priv->ah->caps.keycache_size;
554fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (common->keymax > ATH_KEYMAX) {
555fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_ANY,
556fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "Warning, using only %u entries in %u key cache\n",
557fb9987d0f748c983bb795a86f47522313f701a08Sujith			  ATH_KEYMAX, common->keymax);
558fb9987d0f748c983bb795a86f47522313f701a08Sujith		common->keymax = ATH_KEYMAX;
559fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
560fb9987d0f748c983bb795a86f47522313f701a08Sujith
561fb9987d0f748c983bb795a86f47522313f701a08Sujith	/*
562fb9987d0f748c983bb795a86f47522313f701a08Sujith	 * Reset the key cache since some parts do not
563fb9987d0f748c983bb795a86f47522313f701a08Sujith	 * reset the contents on initial power up.
564fb9987d0f748c983bb795a86f47522313f701a08Sujith	 */
565fb9987d0f748c983bb795a86f47522313f701a08Sujith	for (i = 0; i < common->keymax; i++)
566fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_hw_keyreset(priv->ah, (u16) i);
567fb9987d0f748c983bb795a86f47522313f701a08Sujith}
568fb9987d0f748c983bb795a86f47522313f701a08Sujith
569fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
570fb9987d0f748c983bb795a86f47522313f701a08Sujith{
571fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes)) {
572fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].channels =
573fb9987d0f748c983bb795a86f47522313f701a08Sujith			ath9k_2ghz_channels;
574fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
575fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].n_channels =
576fb9987d0f748c983bb795a86f47522313f701a08Sujith			ARRAY_SIZE(ath9k_2ghz_channels);
577fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
578fb9987d0f748c983bb795a86f47522313f701a08Sujith		priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
579fb9987d0f748c983bb795a86f47522313f701a08Sujith			ARRAY_SIZE(ath9k_legacy_rates);
580fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
581ea46e644e80bd4ac778964afd998df4f666486d4Sujith
582ea46e644e80bd4ac778964afd998df4f666486d4Sujith	if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes)) {
583ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels;
584ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
585ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].n_channels =
586ea46e644e80bd4ac778964afd998df4f666486d4Sujith			ARRAY_SIZE(ath9k_5ghz_channels);
587ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].bitrates =
588ea46e644e80bd4ac778964afd998df4f666486d4Sujith			ath9k_legacy_rates + 4;
589ea46e644e80bd4ac778964afd998df4f666486d4Sujith		priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
590ea46e644e80bd4ac778964afd998df4f666486d4Sujith			ARRAY_SIZE(ath9k_legacy_rates) - 4;
591ea46e644e80bd4ac778964afd998df4f666486d4Sujith	}
592fb9987d0f748c983bb795a86f47522313f701a08Sujith}
593fb9987d0f748c983bb795a86f47522313f701a08Sujith
594fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_init_misc(struct ath9k_htc_priv *priv)
595fb9987d0f748c983bb795a86f47522313f701a08Sujith{
596fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
597fb9987d0f748c983bb795a86f47522313f701a08Sujith
598fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->tx_chainmask = priv->ah->caps.tx_chainmask;
599fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->rx_chainmask = priv->ah->caps.rx_chainmask;
600fb9987d0f748c983bb795a86f47522313f701a08Sujith
601fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
602fb9987d0f748c983bb795a86f47522313f701a08Sujith		memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
603fb9987d0f748c983bb795a86f47522313f701a08Sujith
6049f01a84e81d10e38daa504348217895fe414a24bSujith	priv->ah->opmode = NL80211_IFTYPE_STATION;
605fb9987d0f748c983bb795a86f47522313f701a08Sujith}
606fb9987d0f748c983bb795a86f47522313f701a08Sujith
607fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid)
608fb9987d0f748c983bb795a86f47522313f701a08Sujith{
609fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah = NULL;
610fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common;
611fb9987d0f748c983bb795a86f47522313f701a08Sujith	int ret = 0, csz = 0;
612fb9987d0f748c983bb795a86f47522313f701a08Sujith
613fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->op_flags |= OP_INVALID;
614fb9987d0f748c983bb795a86f47522313f701a08Sujith
615fb9987d0f748c983bb795a86f47522313f701a08Sujith	ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
616fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!ah)
617fb9987d0f748c983bb795a86f47522313f701a08Sujith		return -ENOMEM;
618fb9987d0f748c983bb795a86f47522313f701a08Sujith
619fb9987d0f748c983bb795a86f47522313f701a08Sujith	ah->hw_version.devid = devid;
620fb9987d0f748c983bb795a86f47522313f701a08Sujith	ah->hw_version.subsysid = 0; /* FIXME */
621fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->ah = ah;
622fb9987d0f748c983bb795a86f47522313f701a08Sujith
623fb9987d0f748c983bb795a86f47522313f701a08Sujith	common = ath9k_hw_common(ah);
624fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->ops = &ath9k_common_ops;
625fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->bus_ops = &ath9k_usb_bus_ops;
626fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->ah = ah;
627fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->hw = priv->hw;
628fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->priv = priv;
629fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->debug_mask = ath9k_debug;
630fb9987d0f748c983bb795a86f47522313f701a08Sujith
631fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock_init(&priv->wmi->wmi_lock);
632fb9987d0f748c983bb795a86f47522313f701a08Sujith	spin_lock_init(&priv->beacon_lock);
6337757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith	spin_lock_init(&priv->tx_lock);
634fb9987d0f748c983bb795a86f47522313f701a08Sujith	mutex_init(&priv->mutex);
635bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan	mutex_init(&priv->htc_pm_lock);
636fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet,
637fb9987d0f748c983bb795a86f47522313f701a08Sujith		     (unsigned long)priv);
638fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
639fb9987d0f748c983bb795a86f47522313f701a08Sujith		     (unsigned long)priv);
640fb9987d0f748c983bb795a86f47522313f701a08Sujith	tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv);
641fb9987d0f748c983bb795a86f47522313f701a08Sujith	INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work);
642bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan	INIT_WORK(&priv->ps_work, ath9k_ps_work);
643fb9987d0f748c983bb795a86f47522313f701a08Sujith
644fb9987d0f748c983bb795a86f47522313f701a08Sujith	/*
645fb9987d0f748c983bb795a86f47522313f701a08Sujith	 * Cache line size is used to size and align various
646fb9987d0f748c983bb795a86f47522313f701a08Sujith	 * structures used to communicate with the hardware.
647fb9987d0f748c983bb795a86f47522313f701a08Sujith	 */
648fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath_read_cachesize(common, &csz);
649fb9987d0f748c983bb795a86f47522313f701a08Sujith	common->cachelsz = csz << 2; /* convert to bytes */
650fb9987d0f748c983bb795a86f47522313f701a08Sujith
651fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_hw_init(ah);
652fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret) {
653fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_FATAL,
654fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "Unable to initialize hardware; "
655fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "initialization status: %d\n", ret);
656fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_hw;
657fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
658fb9987d0f748c983bb795a86f47522313f701a08Sujith
659e1572c5eeca8ef87a250322364584458b2dadb35Sujith	ret = ath9k_htc_init_debug(ah);
660fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret) {
661fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath_print(common, ATH_DBG_FATAL,
662fb9987d0f748c983bb795a86f47522313f701a08Sujith			  "Unable to create debugfs files\n");
663fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_debug;
664fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
665fb9987d0f748c983bb795a86f47522313f701a08Sujith
666fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_init_queues(priv);
667fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
668fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_queues;
669fb9987d0f748c983bb795a86f47522313f701a08Sujith
670fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_init_crypto(priv);
671fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_init_channels_rates(priv);
672fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_init_misc(priv);
673fb9987d0f748c983bb795a86f47522313f701a08Sujith
674fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
675fb9987d0f748c983bb795a86f47522313f701a08Sujith
676fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_queues:
677e1572c5eeca8ef87a250322364584458b2dadb35Sujith	ath9k_htc_exit_debug(ah);
678fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_debug:
679fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hw_deinit(ah);
680fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_hw:
681fb9987d0f748c983bb795a86f47522313f701a08Sujith
682fb9987d0f748c983bb795a86f47522313f701a08Sujith	kfree(ah);
683fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->ah = NULL;
684fb9987d0f748c983bb795a86f47522313f701a08Sujith
685fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ret;
686fb9987d0f748c983bb795a86f47522313f701a08Sujith}
687fb9987d0f748c983bb795a86f47522313f701a08Sujith
688fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
689fb9987d0f748c983bb795a86f47522313f701a08Sujith			       struct ieee80211_hw *hw)
690fb9987d0f748c983bb795a86f47522313f701a08Sujith{
691fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common = ath9k_hw_common(priv->ah);
692fb9987d0f748c983bb795a86f47522313f701a08Sujith
693fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->flags = IEEE80211_HW_SIGNAL_DBM |
694fb9987d0f748c983bb795a86f47522313f701a08Sujith		IEEE80211_HW_AMPDU_AGGREGATION |
695fb9987d0f748c983bb795a86f47522313f701a08Sujith		IEEE80211_HW_SPECTRUM_MGMT |
69632fbccafed7e935432b601f0453c2b702a385a25Sujith		IEEE80211_HW_HAS_RATE_CONTROL |
697bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan		IEEE80211_HW_RX_INCLUDES_FCS |
698bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan		IEEE80211_HW_SUPPORTS_PS |
699bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan		IEEE80211_HW_PS_NULLFUNC_STACK;
700fb9987d0f748c983bb795a86f47522313f701a08Sujith
701fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->wiphy->interface_modes =
702fb9987d0f748c983bb795a86f47522313f701a08Sujith		BIT(NL80211_IFTYPE_STATION) |
703fb9987d0f748c983bb795a86f47522313f701a08Sujith		BIT(NL80211_IFTYPE_ADHOC);
704fb9987d0f748c983bb795a86f47522313f701a08Sujith
705bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
706bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan
707fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->queues = 4;
708fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->channel_change_time = 5000;
709fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->max_listen_interval = 10;
710fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->vif_data_size = sizeof(struct ath9k_htc_vif);
711fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->sta_data_size = sizeof(struct ath9k_htc_sta);
712fb9987d0f748c983bb795a86f47522313f701a08Sujith
713fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* tx_frame_hdr is larger than tx_mgmt_hdr anyway */
714fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw->extra_tx_headroom = sizeof(struct tx_frame_hdr) +
715fb9987d0f748c983bb795a86f47522313f701a08Sujith		sizeof(struct htc_frame_hdr) + 4;
716fb9987d0f748c983bb795a86f47522313f701a08Sujith
717fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes))
718fb9987d0f748c983bb795a86f47522313f701a08Sujith		hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
719fb9987d0f748c983bb795a86f47522313f701a08Sujith			&priv->sbands[IEEE80211_BAND_2GHZ];
720ea46e644e80bd4ac778964afd998df4f666486d4Sujith	if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes))
721ea46e644e80bd4ac778964afd998df4f666486d4Sujith		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
722ea46e644e80bd4ac778964afd998df4f666486d4Sujith			&priv->sbands[IEEE80211_BAND_5GHZ];
723fb9987d0f748c983bb795a86f47522313f701a08Sujith
724fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
725fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes))
726fb9987d0f748c983bb795a86f47522313f701a08Sujith			setup_ht_cap(priv,
727fb9987d0f748c983bb795a86f47522313f701a08Sujith				     &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap);
728ea46e644e80bd4ac778964afd998df4f666486d4Sujith		if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes))
729ea46e644e80bd4ac778964afd998df4f666486d4Sujith			setup_ht_cap(priv,
730ea46e644e80bd4ac778964afd998df4f666486d4Sujith				     &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap);
731fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
732fb9987d0f748c983bb795a86f47522313f701a08Sujith
733fb9987d0f748c983bb795a86f47522313f701a08Sujith	SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
734fb9987d0f748c983bb795a86f47522313f701a08Sujith}
735fb9987d0f748c983bb795a86f47522313f701a08Sujith
736fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int ath9k_init_device(struct ath9k_htc_priv *priv, u16 devid)
737fb9987d0f748c983bb795a86f47522313f701a08Sujith{
738fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw = priv->hw;
739fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_common *common;
740fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_hw *ah;
741fb9987d0f748c983bb795a86f47522313f701a08Sujith	int error = 0;
742fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath_regulatory *reg;
743fb9987d0f748c983bb795a86f47522313f701a08Sujith
744fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Bring up device */
745fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ath9k_init_priv(priv, devid);
746fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error != 0)
747fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_init;
748fb9987d0f748c983bb795a86f47522313f701a08Sujith
749fb9987d0f748c983bb795a86f47522313f701a08Sujith	ah = priv->ah;
750fb9987d0f748c983bb795a86f47522313f701a08Sujith	common = ath9k_hw_common(ah);
751fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_set_hw_capab(priv, hw);
752fb9987d0f748c983bb795a86f47522313f701a08Sujith
753fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Initialize regulatory */
754fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ath_regd_init(&common->regulatory, priv->hw->wiphy,
755fb9987d0f748c983bb795a86f47522313f701a08Sujith			      ath9k_reg_notifier);
756fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error)
757fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_regd;
758fb9987d0f748c983bb795a86f47522313f701a08Sujith
759fb9987d0f748c983bb795a86f47522313f701a08Sujith	reg = &common->regulatory;
760fb9987d0f748c983bb795a86f47522313f701a08Sujith
761fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Setup TX */
762fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ath9k_tx_init(priv);
763fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error != 0)
764fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_tx;
765fb9987d0f748c983bb795a86f47522313f701a08Sujith
766fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Setup RX */
767fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ath9k_rx_init(priv);
768fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error != 0)
769fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_rx;
770fb9987d0f748c983bb795a86f47522313f701a08Sujith
771fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Register with mac80211 */
772fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ieee80211_register_hw(hw);
773fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error)
774fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_register;
775fb9987d0f748c983bb795a86f47522313f701a08Sujith
776fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Handle world regulatory */
777fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!ath_is_world_regd(reg)) {
778fb9987d0f748c983bb795a86f47522313f701a08Sujith		error = regulatory_hint(hw->wiphy, reg->alpha2);
779fb9987d0f748c983bb795a86f47522313f701a08Sujith		if (error)
780fb9987d0f748c983bb795a86f47522313f701a08Sujith			goto err_world;
781fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
782fb9987d0f748c983bb795a86f47522313f701a08Sujith
783fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_init_leds(priv);
784fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_start_rfkill_poll(priv);
785fb9987d0f748c983bb795a86f47522313f701a08Sujith
786fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
787fb9987d0f748c983bb795a86f47522313f701a08Sujith
788fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_world:
789fb9987d0f748c983bb795a86f47522313f701a08Sujith	ieee80211_unregister_hw(hw);
790fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_register:
791fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_rx_cleanup(priv);
792fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_rx:
793fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_tx_cleanup(priv);
794fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_tx:
795fb9987d0f748c983bb795a86f47522313f701a08Sujith	/* Nothing */
796fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_regd:
797fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_deinit_priv(priv);
798fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_init:
799fb9987d0f748c983bb795a86f47522313f701a08Sujith	return error;
800fb9987d0f748c983bb795a86f47522313f701a08Sujith}
801fb9987d0f748c983bb795a86f47522313f701a08Sujith
802fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
803fb9987d0f748c983bb795a86f47522313f701a08Sujith			   u16 devid)
804fb9987d0f748c983bb795a86f47522313f701a08Sujith{
805fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ieee80211_hw *hw;
806fb9987d0f748c983bb795a86f47522313f701a08Sujith	struct ath9k_htc_priv *priv;
807fb9987d0f748c983bb795a86f47522313f701a08Sujith	int ret;
808fb9987d0f748c983bb795a86f47522313f701a08Sujith
809fb9987d0f748c983bb795a86f47522313f701a08Sujith	hw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), &ath9k_htc_ops);
810fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!hw)
811fb9987d0f748c983bb795a86f47522313f701a08Sujith		return -ENOMEM;
812fb9987d0f748c983bb795a86f47522313f701a08Sujith
813fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv = hw->priv;
814fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->hw = hw;
815fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->htc = htc_handle;
816fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->dev = dev;
817fb9987d0f748c983bb795a86f47522313f701a08Sujith	htc_handle->drv_priv = priv;
818fb9987d0f748c983bb795a86f47522313f701a08Sujith	SET_IEEE80211_DEV(hw, priv->dev);
819fb9987d0f748c983bb795a86f47522313f701a08Sujith
820fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_wait_for_target(priv);
821fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
822fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_free;
823fb9987d0f748c983bb795a86f47522313f701a08Sujith
824fb9987d0f748c983bb795a86f47522313f701a08Sujith	priv->wmi = ath9k_init_wmi(priv);
825fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (!priv->wmi) {
826fb9987d0f748c983bb795a86f47522313f701a08Sujith		ret = -EINVAL;
827fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_free;
828fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
829fb9987d0f748c983bb795a86f47522313f701a08Sujith
8306267dc709c6ef1c0926e18ff2859238992dea658Sujith	ret = ath9k_init_htc_services(priv, devid);
831fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
832fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_init;
833fb9987d0f748c983bb795a86f47522313f701a08Sujith
834a3be14b76da111ebe4d245b0542613f9317104e7Sujith	/* The device may have been unplugged earlier. */
835a3be14b76da111ebe4d245b0542613f9317104e7Sujith	priv->op_flags &= ~OP_UNPLUGGED;
836a3be14b76da111ebe4d245b0542613f9317104e7Sujith
837fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_init_device(priv, devid);
838fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
839fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_init;
840fb9987d0f748c983bb795a86f47522313f701a08Sujith
841fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
842fb9987d0f748c983bb795a86f47522313f701a08Sujith
843fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_init:
844fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_deinit_wmi(priv);
845fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_free:
846fb9987d0f748c983bb795a86f47522313f701a08Sujith	ieee80211_free_hw(hw);
847fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ret;
848fb9987d0f748c983bb795a86f47522313f701a08Sujith}
849fb9987d0f748c983bb795a86f47522313f701a08Sujith
850fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug)
851fb9987d0f748c983bb795a86f47522313f701a08Sujith{
852fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (htc_handle->drv_priv) {
853a3be14b76da111ebe4d245b0542613f9317104e7Sujith
854a3be14b76da111ebe4d245b0542613f9317104e7Sujith		/* Check if the device has been yanked out. */
855a3be14b76da111ebe4d245b0542613f9317104e7Sujith		if (hotunplug)
856a3be14b76da111ebe4d245b0542613f9317104e7Sujith			htc_handle->drv_priv->op_flags |= OP_UNPLUGGED;
857a3be14b76da111ebe4d245b0542613f9317104e7Sujith
858fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_deinit_device(htc_handle->drv_priv);
859fb9987d0f748c983bb795a86f47522313f701a08Sujith		ath9k_deinit_wmi(htc_handle->drv_priv);
860fb9987d0f748c983bb795a86f47522313f701a08Sujith		ieee80211_free_hw(htc_handle->drv_priv->hw);
861fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
862fb9987d0f748c983bb795a86f47522313f701a08Sujith}
863fb9987d0f748c983bb795a86f47522313f701a08Sujith
864fb9987d0f748c983bb795a86f47522313f701a08Sujith#ifdef CONFIG_PM
865fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_htc_resume(struct htc_target *htc_handle)
866fb9987d0f748c983bb795a86f47522313f701a08Sujith{
867fb9987d0f748c983bb795a86f47522313f701a08Sujith	int ret;
868fb9987d0f748c983bb795a86f47522313f701a08Sujith
869fb9987d0f748c983bb795a86f47522313f701a08Sujith	ret = ath9k_htc_wait_for_target(htc_handle->drv_priv);
870fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (ret)
871fb9987d0f748c983bb795a86f47522313f701a08Sujith		return ret;
872fb9987d0f748c983bb795a86f47522313f701a08Sujith
8736267dc709c6ef1c0926e18ff2859238992dea658Sujith	ret = ath9k_init_htc_services(htc_handle->drv_priv,
8746267dc709c6ef1c0926e18ff2859238992dea658Sujith			      htc_handle->drv_priv->ah->hw_version.devid);
875fb9987d0f748c983bb795a86f47522313f701a08Sujith	return ret;
876fb9987d0f748c983bb795a86f47522313f701a08Sujith}
877fb9987d0f748c983bb795a86f47522313f701a08Sujith#endif
878fb9987d0f748c983bb795a86f47522313f701a08Sujith
879fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic int __init ath9k_htc_init(void)
880fb9987d0f748c983bb795a86f47522313f701a08Sujith{
881fb9987d0f748c983bb795a86f47522313f701a08Sujith	int error;
882fb9987d0f748c983bb795a86f47522313f701a08Sujith
883e1572c5eeca8ef87a250322364584458b2dadb35Sujith	error = ath9k_htc_debug_create_root();
884fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error < 0) {
885fb9987d0f748c983bb795a86f47522313f701a08Sujith		printk(KERN_ERR
886fb9987d0f748c983bb795a86f47522313f701a08Sujith			"ath9k_htc: Unable to create debugfs root: %d\n",
887fb9987d0f748c983bb795a86f47522313f701a08Sujith			error);
888fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_dbg;
889fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
890fb9987d0f748c983bb795a86f47522313f701a08Sujith
891fb9987d0f748c983bb795a86f47522313f701a08Sujith	error = ath9k_hif_usb_init();
892fb9987d0f748c983bb795a86f47522313f701a08Sujith	if (error < 0) {
893fb9987d0f748c983bb795a86f47522313f701a08Sujith		printk(KERN_ERR
894fb9987d0f748c983bb795a86f47522313f701a08Sujith			"ath9k_htc: No USB devices found,"
895fb9987d0f748c983bb795a86f47522313f701a08Sujith			" driver not installed.\n");
896fb9987d0f748c983bb795a86f47522313f701a08Sujith		error = -ENODEV;
897fb9987d0f748c983bb795a86f47522313f701a08Sujith		goto err_usb;
898fb9987d0f748c983bb795a86f47522313f701a08Sujith	}
899fb9987d0f748c983bb795a86f47522313f701a08Sujith
900fb9987d0f748c983bb795a86f47522313f701a08Sujith	return 0;
901fb9987d0f748c983bb795a86f47522313f701a08Sujith
902fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_usb:
903e1572c5eeca8ef87a250322364584458b2dadb35Sujith	ath9k_htc_debug_remove_root();
904fb9987d0f748c983bb795a86f47522313f701a08Sujitherr_dbg:
905fb9987d0f748c983bb795a86f47522313f701a08Sujith	return error;
906fb9987d0f748c983bb795a86f47522313f701a08Sujith}
907fb9987d0f748c983bb795a86f47522313f701a08Sujithmodule_init(ath9k_htc_init);
908fb9987d0f748c983bb795a86f47522313f701a08Sujith
909fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void __exit ath9k_htc_exit(void)
910fb9987d0f748c983bb795a86f47522313f701a08Sujith{
911fb9987d0f748c983bb795a86f47522313f701a08Sujith	ath9k_hif_usb_exit();
912e1572c5eeca8ef87a250322364584458b2dadb35Sujith	ath9k_htc_debug_remove_root();
913fb9987d0f748c983bb795a86f47522313f701a08Sujith	printk(KERN_INFO "ath9k_htc: Driver unloaded\n");
914fb9987d0f748c983bb795a86f47522313f701a08Sujith}
915fb9987d0f748c983bb795a86f47522313f701a08Sujithmodule_exit(ath9k_htc_exit);
916