blob: 12387950b449bbd53162d5e9bebdb0daabb0d5c9 [file] [log] [blame]
Sujith55624202010-01-08 10:36:02 +05301/*
2 * Copyright (c) 2008-2009 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090017#include <linux/slab.h>
18
Sujith55624202010-01-08 10:36:02 +053019#include "ath9k.h"
20
21static char *dev_info = "ath9k";
22
23MODULE_AUTHOR("Atheros Communications");
24MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
25MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
26MODULE_LICENSE("Dual BSD/GPL");
27
28static unsigned int ath9k_debug = ATH_DBG_DEFAULT;
29module_param_named(debug, ath9k_debug, uint, 0);
30MODULE_PARM_DESC(debug, "Debugging mask");
31
32int modparam_nohwcrypt;
33module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
34MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
35
Vivek Natarajan93dbbcc2010-08-25 19:34:52 +053036int led_blink;
Vivek Natarajan9a75c2f2010-06-22 11:52:37 +053037module_param_named(blink, led_blink, int, 0444);
38MODULE_PARM_DESC(blink, "Enable LED blink on activity");
39
Vasanthakumar Thiagarajan8f5dcb12010-11-26 06:10:06 -080040static int ath9k_btcoex_enable;
41module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444);
42MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
43
Mohammed Shafi Shajakhan4dc35302010-12-14 13:18:28 +053044int ath9k_pm_qos_value = ATH9K_PM_QOS_DEFAULT_VALUE;
45module_param_named(pmqos, ath9k_pm_qos_value, int, S_IRUSR | S_IRGRP | S_IROTH);
46MODULE_PARM_DESC(pmqos, "User specified PM-QOS value");
47
Sujith55624202010-01-08 10:36:02 +053048/* We use the hw_value as an index into our private channel structure */
49
50#define CHAN2G(_freq, _idx) { \
51 .center_freq = (_freq), \
52 .hw_value = (_idx), \
53 .max_power = 20, \
54}
55
56#define CHAN5G(_freq, _idx) { \
57 .band = IEEE80211_BAND_5GHZ, \
58 .center_freq = (_freq), \
59 .hw_value = (_idx), \
60 .max_power = 20, \
61}
62
63/* Some 2 GHz radios are actually tunable on 2312-2732
64 * on 5 MHz steps, we support the channels which we know
65 * we have calibration data for all cards though to make
66 * this static */
Felix Fietkauf209f522010-10-01 01:06:53 +020067static const struct ieee80211_channel ath9k_2ghz_chantable[] = {
Sujith55624202010-01-08 10:36:02 +053068 CHAN2G(2412, 0), /* Channel 1 */
69 CHAN2G(2417, 1), /* Channel 2 */
70 CHAN2G(2422, 2), /* Channel 3 */
71 CHAN2G(2427, 3), /* Channel 4 */
72 CHAN2G(2432, 4), /* Channel 5 */
73 CHAN2G(2437, 5), /* Channel 6 */
74 CHAN2G(2442, 6), /* Channel 7 */
75 CHAN2G(2447, 7), /* Channel 8 */
76 CHAN2G(2452, 8), /* Channel 9 */
77 CHAN2G(2457, 9), /* Channel 10 */
78 CHAN2G(2462, 10), /* Channel 11 */
79 CHAN2G(2467, 11), /* Channel 12 */
80 CHAN2G(2472, 12), /* Channel 13 */
81 CHAN2G(2484, 13), /* Channel 14 */
82};
83
84/* Some 5 GHz radios are actually tunable on XXXX-YYYY
85 * on 5 MHz steps, we support the channels which we know
86 * we have calibration data for all cards though to make
87 * this static */
Felix Fietkauf209f522010-10-01 01:06:53 +020088static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
Sujith55624202010-01-08 10:36:02 +053089 /* _We_ call this UNII 1 */
90 CHAN5G(5180, 14), /* Channel 36 */
91 CHAN5G(5200, 15), /* Channel 40 */
92 CHAN5G(5220, 16), /* Channel 44 */
93 CHAN5G(5240, 17), /* Channel 48 */
94 /* _We_ call this UNII 2 */
95 CHAN5G(5260, 18), /* Channel 52 */
96 CHAN5G(5280, 19), /* Channel 56 */
97 CHAN5G(5300, 20), /* Channel 60 */
98 CHAN5G(5320, 21), /* Channel 64 */
99 /* _We_ call this "Middle band" */
100 CHAN5G(5500, 22), /* Channel 100 */
101 CHAN5G(5520, 23), /* Channel 104 */
102 CHAN5G(5540, 24), /* Channel 108 */
103 CHAN5G(5560, 25), /* Channel 112 */
104 CHAN5G(5580, 26), /* Channel 116 */
105 CHAN5G(5600, 27), /* Channel 120 */
106 CHAN5G(5620, 28), /* Channel 124 */
107 CHAN5G(5640, 29), /* Channel 128 */
108 CHAN5G(5660, 30), /* Channel 132 */
109 CHAN5G(5680, 31), /* Channel 136 */
110 CHAN5G(5700, 32), /* Channel 140 */
111 /* _We_ call this UNII 3 */
112 CHAN5G(5745, 33), /* Channel 149 */
113 CHAN5G(5765, 34), /* Channel 153 */
114 CHAN5G(5785, 35), /* Channel 157 */
115 CHAN5G(5805, 36), /* Channel 161 */
116 CHAN5G(5825, 37), /* Channel 165 */
117};
118
119/* Atheros hardware rate code addition for short premble */
120#define SHPCHECK(__hw_rate, __flags) \
121 ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
122
123#define RATE(_bitrate, _hw_rate, _flags) { \
124 .bitrate = (_bitrate), \
125 .flags = (_flags), \
126 .hw_value = (_hw_rate), \
127 .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \
128}
129
130static struct ieee80211_rate ath9k_legacy_rates[] = {
131 RATE(10, 0x1b, 0),
132 RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
133 RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
134 RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
135 RATE(60, 0x0b, 0),
136 RATE(90, 0x0f, 0),
137 RATE(120, 0x0a, 0),
138 RATE(180, 0x0e, 0),
139 RATE(240, 0x09, 0),
140 RATE(360, 0x0d, 0),
141 RATE(480, 0x08, 0),
142 RATE(540, 0x0c, 0),
143};
144
Sujith285f2dd2010-01-08 10:36:07 +0530145static void ath9k_deinit_softc(struct ath_softc *sc);
Sujith55624202010-01-08 10:36:02 +0530146
147/*
148 * Read and write, they both share the same lock. We do this to serialize
149 * reads and writes on Atheros 802.11n PCI devices only. This is required
150 * as the FIFO on these devices can only accept sanely 2 requests.
151 */
152
153static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
154{
155 struct ath_hw *ah = (struct ath_hw *) hw_priv;
156 struct ath_common *common = ath9k_hw_common(ah);
157 struct ath_softc *sc = (struct ath_softc *) common->priv;
158
159 if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
160 unsigned long flags;
161 spin_lock_irqsave(&sc->sc_serial_rw, flags);
162 iowrite32(val, sc->mem + reg_offset);
163 spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
164 } else
165 iowrite32(val, sc->mem + reg_offset);
166}
167
168static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
169{
170 struct ath_hw *ah = (struct ath_hw *) hw_priv;
171 struct ath_common *common = ath9k_hw_common(ah);
172 struct ath_softc *sc = (struct ath_softc *) common->priv;
173 u32 val;
174
175 if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
176 unsigned long flags;
177 spin_lock_irqsave(&sc->sc_serial_rw, flags);
178 val = ioread32(sc->mem + reg_offset);
179 spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
180 } else
181 val = ioread32(sc->mem + reg_offset);
182 return val;
183}
184
185static const struct ath_ops ath9k_common_ops = {
186 .read = ath9k_ioread32,
187 .write = ath9k_iowrite32,
188};
189
190/**************************/
191/* Initialization */
192/**************************/
193
194static void setup_ht_cap(struct ath_softc *sc,
195 struct ieee80211_sta_ht_cap *ht_info)
196{
Felix Fietkau3bb065a2010-04-19 19:57:34 +0200197 struct ath_hw *ah = sc->sc_ah;
198 struct ath_common *common = ath9k_hw_common(ah);
Sujith55624202010-01-08 10:36:02 +0530199 u8 tx_streams, rx_streams;
Felix Fietkau3bb065a2010-04-19 19:57:34 +0200200 int i, max_streams;
Sujith55624202010-01-08 10:36:02 +0530201
202 ht_info->ht_supported = true;
203 ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
204 IEEE80211_HT_CAP_SM_PS |
205 IEEE80211_HT_CAP_SGI_40 |
206 IEEE80211_HT_CAP_DSSSCCK40;
207
Luis R. Rodriguezb0a33442010-04-15 17:39:39 -0400208 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC)
209 ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
210
Vasanthakumar Thiagarajan6473d242010-05-13 18:42:38 -0700211 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
212 ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
213
Sujith55624202010-01-08 10:36:02 +0530214 ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
215 ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
216
Vasanthakumar Thiagarajan7f1c7a62010-12-06 04:27:41 -0800217 if (AR_SREV_9485(ah))
218 max_streams = 1;
219 else if (AR_SREV_9300_20_OR_LATER(ah))
Felix Fietkau3bb065a2010-04-19 19:57:34 +0200220 max_streams = 3;
221 else
222 max_streams = 2;
223
Felix Fietkau7a370812010-09-22 12:34:52 +0200224 if (AR_SREV_9280_20_OR_LATER(ah)) {
Felix Fietkau074a8c02010-04-19 19:57:36 +0200225 if (max_streams >= 2)
226 ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
227 ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
228 }
229
Sujith55624202010-01-08 10:36:02 +0530230 /* set up supported mcs set */
231 memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
Sujith61389f32010-06-02 15:53:37 +0530232 tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, max_streams);
233 rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, max_streams);
Felix Fietkau3bb065a2010-04-19 19:57:34 +0200234
Joe Perches226afe62010-12-02 19:12:37 -0800235 ath_dbg(common, ATH_DBG_CONFIG,
236 "TX streams %d, RX streams: %d\n",
237 tx_streams, rx_streams);
Sujith55624202010-01-08 10:36:02 +0530238
239 if (tx_streams != rx_streams) {
Sujith55624202010-01-08 10:36:02 +0530240 ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
241 ht_info->mcs.tx_params |= ((tx_streams - 1) <<
242 IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
243 }
244
Felix Fietkau3bb065a2010-04-19 19:57:34 +0200245 for (i = 0; i < rx_streams; i++)
246 ht_info->mcs.rx_mask[i] = 0xff;
Sujith55624202010-01-08 10:36:02 +0530247
248 ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
249}
250
251static int ath9k_reg_notifier(struct wiphy *wiphy,
252 struct regulatory_request *request)
253{
254 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
255 struct ath_wiphy *aphy = hw->priv;
256 struct ath_softc *sc = aphy->sc;
257 struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah);
258
259 return ath_reg_notifier_apply(wiphy, request, reg);
260}
261
262/*
263 * This function will allocate both the DMA descriptor structure, and the
264 * buffers it contains. These are used to contain the descriptors used
265 * by the system.
266*/
267int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
268 struct list_head *head, const char *name,
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -0400269 int nbuf, int ndesc, bool is_tx)
Sujith55624202010-01-08 10:36:02 +0530270{
271#define DS2PHYS(_dd, _ds) \
272 ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
273#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
274#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
275 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -0400276 u8 *ds;
Sujith55624202010-01-08 10:36:02 +0530277 struct ath_buf *bf;
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -0400278 int i, bsize, error, desc_len;
Sujith55624202010-01-08 10:36:02 +0530279
Joe Perches226afe62010-12-02 19:12:37 -0800280 ath_dbg(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
281 name, nbuf, ndesc);
Sujith55624202010-01-08 10:36:02 +0530282
283 INIT_LIST_HEAD(head);
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -0400284
285 if (is_tx)
286 desc_len = sc->sc_ah->caps.tx_desc_len;
287 else
288 desc_len = sizeof(struct ath_desc);
289
Sujith55624202010-01-08 10:36:02 +0530290 /* ath_desc must be a multiple of DWORDs */
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -0400291 if ((desc_len % 4) != 0) {
Joe Perches38002762010-12-02 19:12:36 -0800292 ath_err(common, "ath_desc not DWORD aligned\n");
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -0400293 BUG_ON((desc_len % 4) != 0);
Sujith55624202010-01-08 10:36:02 +0530294 error = -ENOMEM;
295 goto fail;
296 }
297
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -0400298 dd->dd_desc_len = desc_len * nbuf * ndesc;
Sujith55624202010-01-08 10:36:02 +0530299
300 /*
301 * Need additional DMA memory because we can't use
302 * descriptors that cross the 4K page boundary. Assume
303 * one skipped descriptor per 4K page.
304 */
305 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
306 u32 ndesc_skipped =
307 ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
308 u32 dma_len;
309
310 while (ndesc_skipped) {
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -0400311 dma_len = ndesc_skipped * desc_len;
Sujith55624202010-01-08 10:36:02 +0530312 dd->dd_desc_len += dma_len;
313
314 ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
Joe Perchesee289b62010-05-17 22:47:34 -0700315 }
Sujith55624202010-01-08 10:36:02 +0530316 }
317
318 /* allocate descriptors */
319 dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
320 &dd->dd_desc_paddr, GFP_KERNEL);
321 if (dd->dd_desc == NULL) {
322 error = -ENOMEM;
323 goto fail;
324 }
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -0400325 ds = (u8 *) dd->dd_desc;
Joe Perches226afe62010-12-02 19:12:37 -0800326 ath_dbg(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
327 name, ds, (u32) dd->dd_desc_len,
328 ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
Sujith55624202010-01-08 10:36:02 +0530329
330 /* allocate buffers */
331 bsize = sizeof(struct ath_buf) * nbuf;
332 bf = kzalloc(bsize, GFP_KERNEL);
333 if (bf == NULL) {
334 error = -ENOMEM;
335 goto fail2;
336 }
337 dd->dd_bufptr = bf;
338
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -0400339 for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) {
Sujith55624202010-01-08 10:36:02 +0530340 bf->bf_desc = ds;
341 bf->bf_daddr = DS2PHYS(dd, ds);
342
343 if (!(sc->sc_ah->caps.hw_caps &
344 ATH9K_HW_CAP_4KB_SPLITTRANS)) {
345 /*
346 * Skip descriptor addresses which can cause 4KB
347 * boundary crossing (addr + length) with a 32 dword
348 * descriptor fetch.
349 */
350 while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
351 BUG_ON((caddr_t) bf->bf_desc >=
352 ((caddr_t) dd->dd_desc +
353 dd->dd_desc_len));
354
Vasanthakumar Thiagarajan4adfcde2010-04-15 17:39:33 -0400355 ds += (desc_len * ndesc);
Sujith55624202010-01-08 10:36:02 +0530356 bf->bf_desc = ds;
357 bf->bf_daddr = DS2PHYS(dd, ds);
358 }
359 }
360 list_add_tail(&bf->list, head);
361 }
362 return 0;
363fail2:
364 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
365 dd->dd_desc_paddr);
366fail:
367 memset(dd, 0, sizeof(*dd));
368 return error;
369#undef ATH_DESC_4KB_BOUND_CHECK
370#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
371#undef DS2PHYS
372}
373
Sujith285f2dd2010-01-08 10:36:07 +0530374static void ath9k_init_crypto(struct ath_softc *sc)
Sujith55624202010-01-08 10:36:02 +0530375{
Sujith285f2dd2010-01-08 10:36:07 +0530376 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
377 int i = 0;
Sujith55624202010-01-08 10:36:02 +0530378
379 /* Get the hardware key cache size. */
Sujith285f2dd2010-01-08 10:36:07 +0530380 common->keymax = sc->sc_ah->caps.keycache_size;
Sujith55624202010-01-08 10:36:02 +0530381 if (common->keymax > ATH_KEYMAX) {
Joe Perches226afe62010-12-02 19:12:37 -0800382 ath_dbg(common, ATH_DBG_ANY,
383 "Warning, using only %u entries in %u key cache\n",
384 ATH_KEYMAX, common->keymax);
Sujith55624202010-01-08 10:36:02 +0530385 common->keymax = ATH_KEYMAX;
386 }
387
388 /*
389 * Reset the key cache since some parts do not
390 * reset the contents on initial power up.
391 */
392 for (i = 0; i < common->keymax; i++)
Bruno Randolf040e5392010-09-08 16:05:04 +0900393 ath_hw_keyreset(common, (u16) i);
Sujith55624202010-01-08 10:36:02 +0530394
Felix Fietkau716f7fc2010-06-12 17:22:28 +0200395 /*
Sujith55624202010-01-08 10:36:02 +0530396 * Check whether the separate key cache entries
397 * are required to handle both tx+rx MIC keys.
398 * With split mic keys the number of stations is limited
399 * to 27 otherwise 59.
400 */
Bruno Randolf117675d2010-09-08 16:04:54 +0900401 if (sc->sc_ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
402 common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
Sujith285f2dd2010-01-08 10:36:07 +0530403}
Sujith55624202010-01-08 10:36:02 +0530404
Sujith285f2dd2010-01-08 10:36:07 +0530405static int ath9k_init_btcoex(struct ath_softc *sc)
406{
Felix Fietkau066dae92010-11-07 14:59:39 +0100407 struct ath_txq *txq;
408 int r;
Sujith285f2dd2010-01-08 10:36:07 +0530409
410 switch (sc->sc_ah->btcoex_hw.scheme) {
411 case ATH_BTCOEX_CFG_NONE:
412 break;
413 case ATH_BTCOEX_CFG_2WIRE:
414 ath9k_hw_btcoex_init_2wire(sc->sc_ah);
415 break;
416 case ATH_BTCOEX_CFG_3WIRE:
417 ath9k_hw_btcoex_init_3wire(sc->sc_ah);
418 r = ath_init_btcoex_timer(sc);
419 if (r)
420 return -1;
Felix Fietkau066dae92010-11-07 14:59:39 +0100421 txq = sc->tx.txq_map[WME_AC_BE];
422 ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
Sujith285f2dd2010-01-08 10:36:07 +0530423 sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
424 break;
425 default:
426 WARN_ON(1);
427 break;
Sujith55624202010-01-08 10:36:02 +0530428 }
429
Sujith285f2dd2010-01-08 10:36:07 +0530430 return 0;
431}
Sujith55624202010-01-08 10:36:02 +0530432
Sujith285f2dd2010-01-08 10:36:07 +0530433static int ath9k_init_queues(struct ath_softc *sc)
434{
Sujith285f2dd2010-01-08 10:36:07 +0530435 int i = 0;
Sujith55624202010-01-08 10:36:02 +0530436
Sujith285f2dd2010-01-08 10:36:07 +0530437 sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah);
Sujith285f2dd2010-01-08 10:36:07 +0530438 sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
Sujith55624202010-01-08 10:36:02 +0530439
Sujith285f2dd2010-01-08 10:36:07 +0530440 sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
441 ath_cabq_update(sc);
442
Felix Fietkau066dae92010-11-07 14:59:39 +0100443 for (i = 0; i < WME_NUM_AC; i++)
444 sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
Sujith285f2dd2010-01-08 10:36:07 +0530445
446 return 0;
Sujith285f2dd2010-01-08 10:36:07 +0530447}
448
Felix Fietkauf209f522010-10-01 01:06:53 +0200449static int ath9k_init_channels_rates(struct ath_softc *sc)
Sujith285f2dd2010-01-08 10:36:07 +0530450{
Felix Fietkauf209f522010-10-01 01:06:53 +0200451 void *channels;
452
Felix Fietkaucac42202010-10-09 02:39:30 +0200453 BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) +
454 ARRAY_SIZE(ath9k_5ghz_chantable) !=
455 ATH9K_NUM_CHANNELS);
456
Felix Fietkaud4659912010-10-14 16:02:39 +0200457 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
Felix Fietkauf209f522010-10-01 01:06:53 +0200458 channels = kmemdup(ath9k_2ghz_chantable,
459 sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
460 if (!channels)
461 return -ENOMEM;
462
463 sc->sbands[IEEE80211_BAND_2GHZ].channels = channels;
Sujith55624202010-01-08 10:36:02 +0530464 sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
465 sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
466 ARRAY_SIZE(ath9k_2ghz_chantable);
467 sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
468 sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
469 ARRAY_SIZE(ath9k_legacy_rates);
470 }
471
Felix Fietkaud4659912010-10-14 16:02:39 +0200472 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
Felix Fietkauf209f522010-10-01 01:06:53 +0200473 channels = kmemdup(ath9k_5ghz_chantable,
474 sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
475 if (!channels) {
476 if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
477 kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
478 return -ENOMEM;
479 }
480
481 sc->sbands[IEEE80211_BAND_5GHZ].channels = channels;
Sujith55624202010-01-08 10:36:02 +0530482 sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
483 sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
484 ARRAY_SIZE(ath9k_5ghz_chantable);
485 sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
486 ath9k_legacy_rates + 4;
487 sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
488 ARRAY_SIZE(ath9k_legacy_rates) - 4;
489 }
Felix Fietkauf209f522010-10-01 01:06:53 +0200490 return 0;
Sujith285f2dd2010-01-08 10:36:07 +0530491}
Sujith55624202010-01-08 10:36:02 +0530492
Sujith285f2dd2010-01-08 10:36:07 +0530493static void ath9k_init_misc(struct ath_softc *sc)
494{
495 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
496 int i = 0;
497
Sujith285f2dd2010-01-08 10:36:07 +0530498 setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
499
500 sc->config.txpowlimit = ATH_TXPOWER_MAX;
501
502 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
503 sc->sc_flags |= SC_OP_TXAGGR;
504 sc->sc_flags |= SC_OP_RXAGGR;
Sujith55624202010-01-08 10:36:02 +0530505 }
506
Sujith285f2dd2010-01-08 10:36:07 +0530507 common->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
508 common->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
509
Luis R. Rodriguez8fe65362010-04-15 17:38:14 -0400510 ath9k_hw_set_diversity(sc->sc_ah, true);
Sujith285f2dd2010-01-08 10:36:07 +0530511 sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah);
512
Felix Fietkau364734f2010-09-14 20:22:44 +0200513 memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
Sujith285f2dd2010-01-08 10:36:07 +0530514
515 sc->beacon.slottime = ATH9K_SLOT_TIME_9;
516
517 for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
518 sc->beacon.bslot[i] = NULL;
519 sc->beacon.bslot_aphy[i] = NULL;
520 }
Vasanthakumar Thiagarajan102885a2010-09-02 01:34:43 -0700521
522 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
523 sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
Sujith285f2dd2010-01-08 10:36:07 +0530524}
525
526static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
527 const struct ath_bus_ops *bus_ops)
528{
529 struct ath_hw *ah = NULL;
530 struct ath_common *common;
531 int ret = 0, i;
532 int csz = 0;
533
Sujith285f2dd2010-01-08 10:36:07 +0530534 ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
535 if (!ah)
536 return -ENOMEM;
537
538 ah->hw_version.devid = devid;
539 ah->hw_version.subsysid = subsysid;
540 sc->sc_ah = ah;
541
Felix Fietkaua05b5d452010-11-17 04:25:33 +0100542 if (!sc->dev->platform_data)
543 ah->ah_flags |= AH_USE_EEPROM;
544
Sujith285f2dd2010-01-08 10:36:07 +0530545 common = ath9k_hw_common(ah);
546 common->ops = &ath9k_common_ops;
547 common->bus_ops = bus_ops;
548 common->ah = ah;
549 common->hw = sc->hw;
550 common->priv = sc;
551 common->debug_mask = ath9k_debug;
Vasanthakumar Thiagarajan8f5dcb12010-11-26 06:10:06 -0800552 common->btcoex_enabled = ath9k_btcoex_enable == 1;
Ben Greear20b257442010-10-15 15:04:09 -0700553 spin_lock_init(&common->cc_lock);
Sujith285f2dd2010-01-08 10:36:07 +0530554
555 spin_lock_init(&sc->wiphy_lock);
Sujith285f2dd2010-01-08 10:36:07 +0530556 spin_lock_init(&sc->sc_serial_rw);
557 spin_lock_init(&sc->sc_pm_lock);
558 mutex_init(&sc->mutex);
559 tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
560 tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
561 (unsigned long)sc);
562
563 /*
564 * Cache line size is used to size and align various
565 * structures used to communicate with the hardware.
566 */
567 ath_read_cachesize(common, &csz);
568 common->cachelsz = csz << 2; /* convert to bytes */
569
Luis R. Rodriguezd70357d2010-04-15 17:38:06 -0400570 /* Initializes the hardware for all supported chipsets */
Sujith285f2dd2010-01-08 10:36:07 +0530571 ret = ath9k_hw_init(ah);
Luis R. Rodriguezd70357d2010-04-15 17:38:06 -0400572 if (ret)
Sujith285f2dd2010-01-08 10:36:07 +0530573 goto err_hw;
Sujith285f2dd2010-01-08 10:36:07 +0530574
Sujith285f2dd2010-01-08 10:36:07 +0530575 ret = ath9k_init_queues(sc);
576 if (ret)
577 goto err_queues;
578
579 ret = ath9k_init_btcoex(sc);
580 if (ret)
581 goto err_btcoex;
582
Felix Fietkauf209f522010-10-01 01:06:53 +0200583 ret = ath9k_init_channels_rates(sc);
584 if (ret)
585 goto err_btcoex;
586
Sujith285f2dd2010-01-08 10:36:07 +0530587 ath9k_init_crypto(sc);
Sujith285f2dd2010-01-08 10:36:07 +0530588 ath9k_init_misc(sc);
589
Sujith55624202010-01-08 10:36:02 +0530590 return 0;
Sujith285f2dd2010-01-08 10:36:07 +0530591
592err_btcoex:
Sujith55624202010-01-08 10:36:02 +0530593 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
594 if (ATH_TXQ_SETUP(sc, i))
595 ath_tx_cleanupq(sc, &sc->tx.txq[i]);
Sujith285f2dd2010-01-08 10:36:07 +0530596err_queues:
Sujith285f2dd2010-01-08 10:36:07 +0530597 ath9k_hw_deinit(ah);
598err_hw:
599 tasklet_kill(&sc->intr_tq);
600 tasklet_kill(&sc->bcon_tasklet);
Sujith55624202010-01-08 10:36:02 +0530601
Sujith285f2dd2010-01-08 10:36:07 +0530602 kfree(ah);
603 sc->sc_ah = NULL;
604
605 return ret;
Sujith55624202010-01-08 10:36:02 +0530606}
607
Felix Fietkaubabcbc22010-10-20 02:09:46 +0200608static void ath9k_init_band_txpower(struct ath_softc *sc, int band)
609{
610 struct ieee80211_supported_band *sband;
611 struct ieee80211_channel *chan;
612 struct ath_hw *ah = sc->sc_ah;
613 struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
614 int i;
615
616 sband = &sc->sbands[band];
617 for (i = 0; i < sband->n_channels; i++) {
618 chan = &sband->channels[i];
619 ah->curchan = &ah->channels[chan->hw_value];
620 ath9k_cmn_update_ichannel(ah->curchan, chan, NL80211_CHAN_HT20);
621 ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true);
622 chan->max_power = reg->max_power_level / 2;
623 }
624}
625
626static void ath9k_init_txpower_limits(struct ath_softc *sc)
627{
628 struct ath_hw *ah = sc->sc_ah;
629 struct ath9k_channel *curchan = ah->curchan;
630
631 if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
632 ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ);
633 if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
634 ath9k_init_band_txpower(sc, IEEE80211_BAND_5GHZ);
635
636 ah->curchan = curchan;
637}
638
Sujith285f2dd2010-01-08 10:36:07 +0530639void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
Sujith55624202010-01-08 10:36:02 +0530640{
Sujith285f2dd2010-01-08 10:36:07 +0530641 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
642
Sujith55624202010-01-08 10:36:02 +0530643 hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
644 IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
645 IEEE80211_HW_SIGNAL_DBM |
Sujith55624202010-01-08 10:36:02 +0530646 IEEE80211_HW_SUPPORTS_PS |
647 IEEE80211_HW_PS_NULLFUNC_STACK |
Vivek Natarajan05df4982010-02-09 11:34:50 +0530648 IEEE80211_HW_SPECTRUM_MGMT |
Mohammed Shafi Shajakhan0ce3bcf2010-12-07 21:14:15 +0530649 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
650 IEEE80211_HW_NEED_DTIM_PERIOD;
Sujith55624202010-01-08 10:36:02 +0530651
Luis R. Rodriguez5ffaf8a2010-02-02 11:58:33 -0500652 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
653 hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
654
Sujith55624202010-01-08 10:36:02 +0530655 if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt)
656 hw->flags |= IEEE80211_HW_MFP_CAPABLE;
657
658 hw->wiphy->interface_modes =
Johannes Bergc426ee22010-11-26 11:38:04 +0100659 BIT(NL80211_IFTYPE_P2P_GO) |
660 BIT(NL80211_IFTYPE_P2P_CLIENT) |
Sujith55624202010-01-08 10:36:02 +0530661 BIT(NL80211_IFTYPE_AP) |
Bill Jordane51f3ef2010-10-01 11:20:39 -0400662 BIT(NL80211_IFTYPE_WDS) |
Sujith55624202010-01-08 10:36:02 +0530663 BIT(NL80211_IFTYPE_STATION) |
664 BIT(NL80211_IFTYPE_ADHOC) |
665 BIT(NL80211_IFTYPE_MESH_POINT);
666
Luis R. Rodriguez008443d2010-09-16 15:12:36 -0400667 if (AR_SREV_5416(sc->sc_ah))
668 hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
Sujith55624202010-01-08 10:36:02 +0530669
670 hw->queues = 4;
671 hw->max_rates = 4;
672 hw->channel_change_time = 5000;
673 hw->max_listen_interval = 10;
Felix Fietkau65896512010-01-24 03:26:11 +0100674 hw->max_rate_tries = 10;
Sujith55624202010-01-08 10:36:02 +0530675 hw->sta_data_size = sizeof(struct ath_node);
676 hw->vif_data_size = sizeof(struct ath_vif);
677
Felix Fietkau6e5c2b42010-09-20 13:45:40 +0200678#ifdef CONFIG_ATH9K_RATE_CONTROL
Sujith55624202010-01-08 10:36:02 +0530679 hw->rate_control_algorithm = "ath9k_rate_control";
Felix Fietkau6e5c2b42010-09-20 13:45:40 +0200680#endif
Sujith55624202010-01-08 10:36:02 +0530681
Felix Fietkaud4659912010-10-14 16:02:39 +0200682 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
Sujith55624202010-01-08 10:36:02 +0530683 hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
684 &sc->sbands[IEEE80211_BAND_2GHZ];
Felix Fietkaud4659912010-10-14 16:02:39 +0200685 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
Sujith55624202010-01-08 10:36:02 +0530686 hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
687 &sc->sbands[IEEE80211_BAND_5GHZ];
Sujith285f2dd2010-01-08 10:36:07 +0530688
689 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
Felix Fietkaud4659912010-10-14 16:02:39 +0200690 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
Sujith285f2dd2010-01-08 10:36:07 +0530691 setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
Felix Fietkaud4659912010-10-14 16:02:39 +0200692 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
Sujith285f2dd2010-01-08 10:36:07 +0530693 setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
694 }
695
696 SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
Sujith55624202010-01-08 10:36:02 +0530697}
698
Sujith285f2dd2010-01-08 10:36:07 +0530699int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
Sujith55624202010-01-08 10:36:02 +0530700 const struct ath_bus_ops *bus_ops)
701{
702 struct ieee80211_hw *hw = sc->hw;
Felix Fietkau9fa23e12010-10-15 20:03:31 +0200703 struct ath_wiphy *aphy = hw->priv;
Sujith55624202010-01-08 10:36:02 +0530704 struct ath_common *common;
705 struct ath_hw *ah;
Sujith285f2dd2010-01-08 10:36:07 +0530706 int error = 0;
Sujith55624202010-01-08 10:36:02 +0530707 struct ath_regulatory *reg;
708
Sujith285f2dd2010-01-08 10:36:07 +0530709 /* Bring up device */
710 error = ath9k_init_softc(devid, sc, subsysid, bus_ops);
Sujith55624202010-01-08 10:36:02 +0530711 if (error != 0)
Sujith285f2dd2010-01-08 10:36:07 +0530712 goto error_init;
Sujith55624202010-01-08 10:36:02 +0530713
714 ah = sc->sc_ah;
715 common = ath9k_hw_common(ah);
Sujith285f2dd2010-01-08 10:36:07 +0530716 ath9k_set_hw_capab(sc, hw);
Sujith55624202010-01-08 10:36:02 +0530717
Sujith285f2dd2010-01-08 10:36:07 +0530718 /* Initialize regulatory */
Sujith55624202010-01-08 10:36:02 +0530719 error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
720 ath9k_reg_notifier);
721 if (error)
Sujith285f2dd2010-01-08 10:36:07 +0530722 goto error_regd;
Sujith55624202010-01-08 10:36:02 +0530723
724 reg = &common->regulatory;
725
Sujith285f2dd2010-01-08 10:36:07 +0530726 /* Setup TX DMA */
Sujith55624202010-01-08 10:36:02 +0530727 error = ath_tx_init(sc, ATH_TXBUF);
728 if (error != 0)
Sujith285f2dd2010-01-08 10:36:07 +0530729 goto error_tx;
Sujith55624202010-01-08 10:36:02 +0530730
Sujith285f2dd2010-01-08 10:36:07 +0530731 /* Setup RX DMA */
Sujith55624202010-01-08 10:36:02 +0530732 error = ath_rx_init(sc, ATH_RXBUF);
733 if (error != 0)
Sujith285f2dd2010-01-08 10:36:07 +0530734 goto error_rx;
735
Felix Fietkaubabcbc22010-10-20 02:09:46 +0200736 ath9k_init_txpower_limits(sc);
737
Sujith285f2dd2010-01-08 10:36:07 +0530738 /* Register with mac80211 */
739 error = ieee80211_register_hw(hw);
740 if (error)
741 goto error_register;
742
Ben Greeareb272442010-11-29 14:13:22 -0800743 error = ath9k_init_debug(ah);
744 if (error) {
Joe Perches38002762010-12-02 19:12:36 -0800745 ath_err(common, "Unable to create debugfs files\n");
Ben Greeareb272442010-11-29 14:13:22 -0800746 goto error_world;
747 }
748
Sujith285f2dd2010-01-08 10:36:07 +0530749 /* Handle world regulatory */
750 if (!ath_is_world_regd(reg)) {
751 error = regulatory_hint(hw->wiphy, reg->alpha2);
752 if (error)
753 goto error_world;
754 }
Sujith55624202010-01-08 10:36:02 +0530755
Felix Fietkau347809f2010-07-02 00:09:52 +0200756 INIT_WORK(&sc->hw_check_work, ath_hw_check);
Felix Fietkau9f42c2b2010-06-12 00:34:01 -0400757 INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
Sujith55624202010-01-08 10:36:02 +0530758 INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
759 INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
760 sc->wiphy_scheduler_int = msecs_to_jiffies(500);
Felix Fietkau9fa23e12010-10-15 20:03:31 +0200761 aphy->last_rssi = ATH_RSSI_DUMMY_MARKER;
Sujith55624202010-01-08 10:36:02 +0530762
Sujith55624202010-01-08 10:36:02 +0530763 ath_init_leds(sc);
Sujith55624202010-01-08 10:36:02 +0530764 ath_start_rfkill_poll(sc);
765
Gabor Juhos98c316e2010-11-25 18:26:07 +0100766 pm_qos_add_request(&sc->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
Vivek Natarajan10598c12010-10-30 22:05:13 +0530767 PM_QOS_DEFAULT_VALUE);
768
Sujith55624202010-01-08 10:36:02 +0530769 return 0;
770
Sujith285f2dd2010-01-08 10:36:07 +0530771error_world:
772 ieee80211_unregister_hw(hw);
773error_register:
774 ath_rx_cleanup(sc);
775error_rx:
776 ath_tx_cleanup(sc);
777error_tx:
778 /* Nothing */
779error_regd:
780 ath9k_deinit_softc(sc);
781error_init:
Sujith55624202010-01-08 10:36:02 +0530782 return error;
783}
784
785/*****************************/
786/* De-Initialization */
787/*****************************/
788
Sujith285f2dd2010-01-08 10:36:07 +0530789static void ath9k_deinit_softc(struct ath_softc *sc)
Sujith55624202010-01-08 10:36:02 +0530790{
Sujith285f2dd2010-01-08 10:36:07 +0530791 int i = 0;
Sujith55624202010-01-08 10:36:02 +0530792
Felix Fietkauf209f522010-10-01 01:06:53 +0200793 if (sc->sbands[IEEE80211_BAND_2GHZ].channels)
794 kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels);
795
796 if (sc->sbands[IEEE80211_BAND_5GHZ].channels)
797 kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels);
798
Sujith285f2dd2010-01-08 10:36:07 +0530799 if ((sc->btcoex.no_stomp_timer) &&
800 sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
801 ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
Sujith55624202010-01-08 10:36:02 +0530802
Sujith285f2dd2010-01-08 10:36:07 +0530803 for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
804 if (ATH_TXQ_SETUP(sc, i))
805 ath_tx_cleanupq(sc, &sc->tx.txq[i]);
806
Sujith285f2dd2010-01-08 10:36:07 +0530807 ath9k_hw_deinit(sc->sc_ah);
808
809 tasklet_kill(&sc->intr_tq);
810 tasklet_kill(&sc->bcon_tasklet);
Sujith736b3a22010-03-17 14:25:24 +0530811
812 kfree(sc->sc_ah);
813 sc->sc_ah = NULL;
Sujith55624202010-01-08 10:36:02 +0530814}
815
Sujith285f2dd2010-01-08 10:36:07 +0530816void ath9k_deinit_device(struct ath_softc *sc)
Sujith55624202010-01-08 10:36:02 +0530817{
818 struct ieee80211_hw *hw = sc->hw;
Sujith55624202010-01-08 10:36:02 +0530819 int i = 0;
820
821 ath9k_ps_wakeup(sc);
822
Sujith55624202010-01-08 10:36:02 +0530823 wiphy_rfkill_stop_polling(sc->hw->wiphy);
Sujith285f2dd2010-01-08 10:36:07 +0530824 ath_deinit_leds(sc);
Sujith55624202010-01-08 10:36:02 +0530825
826 for (i = 0; i < sc->num_sec_wiphy; i++) {
827 struct ath_wiphy *aphy = sc->sec_wiphy[i];
828 if (aphy == NULL)
829 continue;
830 sc->sec_wiphy[i] = NULL;
831 ieee80211_unregister_hw(aphy->hw);
832 ieee80211_free_hw(aphy->hw);
833 }
Sujith285f2dd2010-01-08 10:36:07 +0530834
Sujith55624202010-01-08 10:36:02 +0530835 ieee80211_unregister_hw(hw);
Gabor Juhos98c316e2010-11-25 18:26:07 +0100836 pm_qos_remove_request(&sc->pm_qos_req);
Sujith55624202010-01-08 10:36:02 +0530837 ath_rx_cleanup(sc);
838 ath_tx_cleanup(sc);
Sujith285f2dd2010-01-08 10:36:07 +0530839 ath9k_deinit_softc(sc);
Rajkumar Manoharan447a42c2010-07-08 12:12:29 +0530840 kfree(sc->sec_wiphy);
Sujith55624202010-01-08 10:36:02 +0530841}
842
843void ath_descdma_cleanup(struct ath_softc *sc,
844 struct ath_descdma *dd,
845 struct list_head *head)
846{
847 dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
848 dd->dd_desc_paddr);
849
850 INIT_LIST_HEAD(head);
851 kfree(dd->dd_bufptr);
852 memset(dd, 0, sizeof(*dd));
853}
854
Sujith55624202010-01-08 10:36:02 +0530855/************************/
856/* Module Hooks */
857/************************/
858
859static int __init ath9k_init(void)
860{
861 int error;
862
863 /* Register rate control algorithm */
864 error = ath_rate_control_register();
865 if (error != 0) {
866 printk(KERN_ERR
867 "ath9k: Unable to register rate control "
868 "algorithm: %d\n",
869 error);
870 goto err_out;
871 }
872
Sujith55624202010-01-08 10:36:02 +0530873 error = ath_pci_init();
874 if (error < 0) {
875 printk(KERN_ERR
876 "ath9k: No PCI devices found, driver not installed.\n");
877 error = -ENODEV;
Ben Greeareb272442010-11-29 14:13:22 -0800878 goto err_rate_unregister;
Sujith55624202010-01-08 10:36:02 +0530879 }
880
881 error = ath_ahb_init();
882 if (error < 0) {
883 error = -ENODEV;
884 goto err_pci_exit;
885 }
886
887 return 0;
888
889 err_pci_exit:
890 ath_pci_exit();
891
Sujith55624202010-01-08 10:36:02 +0530892 err_rate_unregister:
893 ath_rate_control_unregister();
894 err_out:
895 return error;
896}
897module_init(ath9k_init);
898
899static void __exit ath9k_exit(void)
900{
901 ath_ahb_exit();
902 ath_pci_exit();
Sujith55624202010-01-08 10:36:02 +0530903 ath_rate_control_unregister();
904 printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
905}
906module_exit(ath9k_exit);