| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 1 | /* | 
 | 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 Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 17 | #include <linux/slab.h> | 
| Felix Fietkau | 6fb1b1e | 2011-03-19 13:55:39 +0100 | [diff] [blame] | 18 | #include <linux/ath9k_platform.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 19 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 20 | #include "ath9k.h" | 
 | 21 |  | 
 | 22 | static char *dev_info = "ath9k"; | 
 | 23 |  | 
 | 24 | MODULE_AUTHOR("Atheros Communications"); | 
 | 25 | MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); | 
 | 26 | MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); | 
 | 27 | MODULE_LICENSE("Dual BSD/GPL"); | 
 | 28 |  | 
 | 29 | static unsigned int ath9k_debug = ATH_DBG_DEFAULT; | 
 | 30 | module_param_named(debug, ath9k_debug, uint, 0); | 
 | 31 | MODULE_PARM_DESC(debug, "Debugging mask"); | 
 | 32 |  | 
| John W. Linville | 3e6109c | 2011-01-05 09:39:17 -0500 | [diff] [blame] | 33 | int ath9k_modparam_nohwcrypt; | 
 | 34 | module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 35 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); | 
 | 36 |  | 
| Vivek Natarajan | 93dbbcc | 2010-08-25 19:34:52 +0530 | [diff] [blame] | 37 | int led_blink; | 
| Vivek Natarajan | 9a75c2f | 2010-06-22 11:52:37 +0530 | [diff] [blame] | 38 | module_param_named(blink, led_blink, int, 0444); | 
 | 39 | MODULE_PARM_DESC(blink, "Enable LED blink on activity"); | 
 | 40 |  | 
| Vasanthakumar Thiagarajan | 8f5dcb1 | 2010-11-26 06:10:06 -0800 | [diff] [blame] | 41 | static int ath9k_btcoex_enable; | 
 | 42 | module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444); | 
 | 43 | MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); | 
 | 44 |  | 
| Rajkumar Manoharan | d584747 | 2010-12-20 14:39:51 +0530 | [diff] [blame] | 45 | bool is_ath9k_unloaded; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 46 | /* We use the hw_value as an index into our private channel structure */ | 
 | 47 |  | 
 | 48 | #define CHAN2G(_freq, _idx)  { \ | 
| Mohammed Shafi Shajakhan | b1c1d00 | 2010-12-17 20:44:36 +0530 | [diff] [blame] | 49 | 	.band = IEEE80211_BAND_2GHZ, \ | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 50 | 	.center_freq = (_freq), \ | 
 | 51 | 	.hw_value = (_idx), \ | 
 | 52 | 	.max_power = 20, \ | 
 | 53 | } | 
 | 54 |  | 
 | 55 | #define CHAN5G(_freq, _idx) { \ | 
 | 56 | 	.band = IEEE80211_BAND_5GHZ, \ | 
 | 57 | 	.center_freq = (_freq), \ | 
 | 58 | 	.hw_value = (_idx), \ | 
 | 59 | 	.max_power = 20, \ | 
 | 60 | } | 
 | 61 |  | 
 | 62 | /* Some 2 GHz radios are actually tunable on 2312-2732 | 
 | 63 |  * on 5 MHz steps, we support the channels which we know | 
 | 64 |  * we have calibration data for all cards though to make | 
 | 65 |  * this static */ | 
| Felix Fietkau | f209f52 | 2010-10-01 01:06:53 +0200 | [diff] [blame] | 66 | static const struct ieee80211_channel ath9k_2ghz_chantable[] = { | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 67 | 	CHAN2G(2412, 0), /* Channel 1 */ | 
 | 68 | 	CHAN2G(2417, 1), /* Channel 2 */ | 
 | 69 | 	CHAN2G(2422, 2), /* Channel 3 */ | 
 | 70 | 	CHAN2G(2427, 3), /* Channel 4 */ | 
 | 71 | 	CHAN2G(2432, 4), /* Channel 5 */ | 
 | 72 | 	CHAN2G(2437, 5), /* Channel 6 */ | 
 | 73 | 	CHAN2G(2442, 6), /* Channel 7 */ | 
 | 74 | 	CHAN2G(2447, 7), /* Channel 8 */ | 
 | 75 | 	CHAN2G(2452, 8), /* Channel 9 */ | 
 | 76 | 	CHAN2G(2457, 9), /* Channel 10 */ | 
 | 77 | 	CHAN2G(2462, 10), /* Channel 11 */ | 
 | 78 | 	CHAN2G(2467, 11), /* Channel 12 */ | 
 | 79 | 	CHAN2G(2472, 12), /* Channel 13 */ | 
 | 80 | 	CHAN2G(2484, 13), /* Channel 14 */ | 
 | 81 | }; | 
 | 82 |  | 
 | 83 | /* Some 5 GHz radios are actually tunable on XXXX-YYYY | 
 | 84 |  * on 5 MHz steps, we support the channels which we know | 
 | 85 |  * we have calibration data for all cards though to make | 
 | 86 |  * this static */ | 
| Felix Fietkau | f209f52 | 2010-10-01 01:06:53 +0200 | [diff] [blame] | 87 | static const struct ieee80211_channel ath9k_5ghz_chantable[] = { | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 88 | 	/* _We_ call this UNII 1 */ | 
 | 89 | 	CHAN5G(5180, 14), /* Channel 36 */ | 
 | 90 | 	CHAN5G(5200, 15), /* Channel 40 */ | 
 | 91 | 	CHAN5G(5220, 16), /* Channel 44 */ | 
 | 92 | 	CHAN5G(5240, 17), /* Channel 48 */ | 
 | 93 | 	/* _We_ call this UNII 2 */ | 
 | 94 | 	CHAN5G(5260, 18), /* Channel 52 */ | 
 | 95 | 	CHAN5G(5280, 19), /* Channel 56 */ | 
 | 96 | 	CHAN5G(5300, 20), /* Channel 60 */ | 
 | 97 | 	CHAN5G(5320, 21), /* Channel 64 */ | 
 | 98 | 	/* _We_ call this "Middle band" */ | 
 | 99 | 	CHAN5G(5500, 22), /* Channel 100 */ | 
 | 100 | 	CHAN5G(5520, 23), /* Channel 104 */ | 
 | 101 | 	CHAN5G(5540, 24), /* Channel 108 */ | 
 | 102 | 	CHAN5G(5560, 25), /* Channel 112 */ | 
 | 103 | 	CHAN5G(5580, 26), /* Channel 116 */ | 
 | 104 | 	CHAN5G(5600, 27), /* Channel 120 */ | 
 | 105 | 	CHAN5G(5620, 28), /* Channel 124 */ | 
 | 106 | 	CHAN5G(5640, 29), /* Channel 128 */ | 
 | 107 | 	CHAN5G(5660, 30), /* Channel 132 */ | 
 | 108 | 	CHAN5G(5680, 31), /* Channel 136 */ | 
 | 109 | 	CHAN5G(5700, 32), /* Channel 140 */ | 
 | 110 | 	/* _We_ call this UNII 3 */ | 
 | 111 | 	CHAN5G(5745, 33), /* Channel 149 */ | 
 | 112 | 	CHAN5G(5765, 34), /* Channel 153 */ | 
 | 113 | 	CHAN5G(5785, 35), /* Channel 157 */ | 
 | 114 | 	CHAN5G(5805, 36), /* Channel 161 */ | 
 | 115 | 	CHAN5G(5825, 37), /* Channel 165 */ | 
 | 116 | }; | 
 | 117 |  | 
 | 118 | /* Atheros hardware rate code addition for short premble */ | 
 | 119 | #define SHPCHECK(__hw_rate, __flags) \ | 
 | 120 | 	((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) | 
 | 121 |  | 
 | 122 | #define RATE(_bitrate, _hw_rate, _flags) {              \ | 
 | 123 | 	.bitrate        = (_bitrate),                   \ | 
 | 124 | 	.flags          = (_flags),                     \ | 
 | 125 | 	.hw_value       = (_hw_rate),                   \ | 
 | 126 | 	.hw_value_short = (SHPCHECK(_hw_rate, _flags))  \ | 
 | 127 | } | 
 | 128 |  | 
 | 129 | static struct ieee80211_rate ath9k_legacy_rates[] = { | 
 | 130 | 	RATE(10, 0x1b, 0), | 
 | 131 | 	RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), | 
 | 132 | 	RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), | 
 | 133 | 	RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), | 
 | 134 | 	RATE(60, 0x0b, 0), | 
 | 135 | 	RATE(90, 0x0f, 0), | 
 | 136 | 	RATE(120, 0x0a, 0), | 
 | 137 | 	RATE(180, 0x0e, 0), | 
 | 138 | 	RATE(240, 0x09, 0), | 
 | 139 | 	RATE(360, 0x0d, 0), | 
 | 140 | 	RATE(480, 0x08, 0), | 
 | 141 | 	RATE(540, 0x0c, 0), | 
 | 142 | }; | 
 | 143 |  | 
| Felix Fietkau | 0cf55c2 | 2011-02-27 22:26:40 +0100 | [diff] [blame] | 144 | #ifdef CONFIG_MAC80211_LEDS | 
 | 145 | static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = { | 
 | 146 | 	{ .throughput = 0 * 1024, .blink_time = 334 }, | 
 | 147 | 	{ .throughput = 1 * 1024, .blink_time = 260 }, | 
 | 148 | 	{ .throughput = 5 * 1024, .blink_time = 220 }, | 
 | 149 | 	{ .throughput = 10 * 1024, .blink_time = 190 }, | 
 | 150 | 	{ .throughput = 20 * 1024, .blink_time = 170 }, | 
 | 151 | 	{ .throughput = 50 * 1024, .blink_time = 150 }, | 
 | 152 | 	{ .throughput = 70 * 1024, .blink_time = 130 }, | 
 | 153 | 	{ .throughput = 100 * 1024, .blink_time = 110 }, | 
 | 154 | 	{ .throughput = 200 * 1024, .blink_time = 80 }, | 
 | 155 | 	{ .throughput = 300 * 1024, .blink_time = 50 }, | 
 | 156 | }; | 
 | 157 | #endif | 
 | 158 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 159 | static void ath9k_deinit_softc(struct ath_softc *sc); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 160 |  | 
 | 161 | /* | 
 | 162 |  * Read and write, they both share the same lock. We do this to serialize | 
 | 163 |  * reads and writes on Atheros 802.11n PCI devices only. This is required | 
 | 164 |  * as the FIFO on these devices can only accept sanely 2 requests. | 
 | 165 |  */ | 
 | 166 |  | 
 | 167 | static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) | 
 | 168 | { | 
 | 169 | 	struct ath_hw *ah = (struct ath_hw *) hw_priv; | 
 | 170 | 	struct ath_common *common = ath9k_hw_common(ah); | 
 | 171 | 	struct ath_softc *sc = (struct ath_softc *) common->priv; | 
 | 172 |  | 
 | 173 | 	if (ah->config.serialize_regmode == SER_REG_MODE_ON) { | 
 | 174 | 		unsigned long flags; | 
 | 175 | 		spin_lock_irqsave(&sc->sc_serial_rw, flags); | 
 | 176 | 		iowrite32(val, sc->mem + reg_offset); | 
 | 177 | 		spin_unlock_irqrestore(&sc->sc_serial_rw, flags); | 
 | 178 | 	} else | 
 | 179 | 		iowrite32(val, sc->mem + reg_offset); | 
 | 180 | } | 
 | 181 |  | 
 | 182 | static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) | 
 | 183 | { | 
 | 184 | 	struct ath_hw *ah = (struct ath_hw *) hw_priv; | 
 | 185 | 	struct ath_common *common = ath9k_hw_common(ah); | 
 | 186 | 	struct ath_softc *sc = (struct ath_softc *) common->priv; | 
 | 187 | 	u32 val; | 
 | 188 |  | 
 | 189 | 	if (ah->config.serialize_regmode == SER_REG_MODE_ON) { | 
 | 190 | 		unsigned long flags; | 
 | 191 | 		spin_lock_irqsave(&sc->sc_serial_rw, flags); | 
 | 192 | 		val = ioread32(sc->mem + reg_offset); | 
 | 193 | 		spin_unlock_irqrestore(&sc->sc_serial_rw, flags); | 
 | 194 | 	} else | 
 | 195 | 		val = ioread32(sc->mem + reg_offset); | 
 | 196 | 	return val; | 
 | 197 | } | 
 | 198 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 199 | /**************************/ | 
 | 200 | /*     Initialization     */ | 
 | 201 | /**************************/ | 
 | 202 |  | 
 | 203 | static void setup_ht_cap(struct ath_softc *sc, | 
 | 204 | 			 struct ieee80211_sta_ht_cap *ht_info) | 
 | 205 | { | 
| Felix Fietkau | 3bb065a | 2010-04-19 19:57:34 +0200 | [diff] [blame] | 206 | 	struct ath_hw *ah = sc->sc_ah; | 
 | 207 | 	struct ath_common *common = ath9k_hw_common(ah); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 208 | 	u8 tx_streams, rx_streams; | 
| Felix Fietkau | 3bb065a | 2010-04-19 19:57:34 +0200 | [diff] [blame] | 209 | 	int i, max_streams; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 210 |  | 
 | 211 | 	ht_info->ht_supported = true; | 
 | 212 | 	ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | 
 | 213 | 		       IEEE80211_HT_CAP_SM_PS | | 
 | 214 | 		       IEEE80211_HT_CAP_SGI_40 | | 
 | 215 | 		       IEEE80211_HT_CAP_DSSSCCK40; | 
 | 216 |  | 
| Luis R. Rodriguez | b0a3344 | 2010-04-15 17:39:39 -0400 | [diff] [blame] | 217 | 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) | 
 | 218 | 		ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; | 
 | 219 |  | 
| Vasanthakumar Thiagarajan | 6473d24 | 2010-05-13 18:42:38 -0700 | [diff] [blame] | 220 | 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) | 
 | 221 | 		ht_info->cap |= IEEE80211_HT_CAP_SGI_20; | 
 | 222 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 223 | 	ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; | 
 | 224 | 	ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; | 
 | 225 |  | 
| Vasanthakumar Thiagarajan | 7f1c7a6 | 2010-12-06 04:27:41 -0800 | [diff] [blame] | 226 | 	if (AR_SREV_9485(ah)) | 
 | 227 | 		max_streams = 1; | 
 | 228 | 	else if (AR_SREV_9300_20_OR_LATER(ah)) | 
| Felix Fietkau | 3bb065a | 2010-04-19 19:57:34 +0200 | [diff] [blame] | 229 | 		max_streams = 3; | 
 | 230 | 	else | 
 | 231 | 		max_streams = 2; | 
 | 232 |  | 
| Felix Fietkau | 7a37081 | 2010-09-22 12:34:52 +0200 | [diff] [blame] | 233 | 	if (AR_SREV_9280_20_OR_LATER(ah)) { | 
| Felix Fietkau | 074a8c0 | 2010-04-19 19:57:36 +0200 | [diff] [blame] | 234 | 		if (max_streams >= 2) | 
 | 235 | 			ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; | 
 | 236 | 		ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); | 
 | 237 | 	} | 
 | 238 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 239 | 	/* set up supported mcs set */ | 
 | 240 | 	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); | 
| Sujith | 61389f3 | 2010-06-02 15:53:37 +0530 | [diff] [blame] | 241 | 	tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, max_streams); | 
 | 242 | 	rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, max_streams); | 
| Felix Fietkau | 3bb065a | 2010-04-19 19:57:34 +0200 | [diff] [blame] | 243 |  | 
| Joe Perches | 226afe6 | 2010-12-02 19:12:37 -0800 | [diff] [blame] | 244 | 	ath_dbg(common, ATH_DBG_CONFIG, | 
 | 245 | 		"TX streams %d, RX streams: %d\n", | 
 | 246 | 		tx_streams, rx_streams); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 247 |  | 
 | 248 | 	if (tx_streams != rx_streams) { | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 249 | 		ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; | 
 | 250 | 		ht_info->mcs.tx_params |= ((tx_streams - 1) << | 
 | 251 | 				IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); | 
 | 252 | 	} | 
 | 253 |  | 
| Felix Fietkau | 3bb065a | 2010-04-19 19:57:34 +0200 | [diff] [blame] | 254 | 	for (i = 0; i < rx_streams; i++) | 
 | 255 | 		ht_info->mcs.rx_mask[i] = 0xff; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 256 |  | 
 | 257 | 	ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; | 
 | 258 | } | 
 | 259 |  | 
 | 260 | static int ath9k_reg_notifier(struct wiphy *wiphy, | 
 | 261 | 			      struct regulatory_request *request) | 
 | 262 | { | 
 | 263 | 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); | 
| Felix Fietkau | 9ac58615 | 2011-01-24 19:23:18 +0100 | [diff] [blame] | 264 | 	struct ath_softc *sc = hw->priv; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 265 | 	struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah); | 
 | 266 |  | 
 | 267 | 	return ath_reg_notifier_apply(wiphy, request, reg); | 
 | 268 | } | 
 | 269 |  | 
 | 270 | /* | 
 | 271 |  *  This function will allocate both the DMA descriptor structure, and the | 
 | 272 |  *  buffers it contains.  These are used to contain the descriptors used | 
 | 273 |  *  by the system. | 
 | 274 | */ | 
 | 275 | int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, | 
 | 276 | 		      struct list_head *head, const char *name, | 
| Vasanthakumar Thiagarajan | 4adfcde | 2010-04-15 17:39:33 -0400 | [diff] [blame] | 277 | 		      int nbuf, int ndesc, bool is_tx) | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 278 | { | 
 | 279 | #define	DS2PHYS(_dd, _ds)						\ | 
 | 280 | 	((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) | 
 | 281 | #define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) | 
 | 282 | #define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) | 
 | 283 | 	struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 
| Vasanthakumar Thiagarajan | 4adfcde | 2010-04-15 17:39:33 -0400 | [diff] [blame] | 284 | 	u8 *ds; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 285 | 	struct ath_buf *bf; | 
| Vasanthakumar Thiagarajan | 4adfcde | 2010-04-15 17:39:33 -0400 | [diff] [blame] | 286 | 	int i, bsize, error, desc_len; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 287 |  | 
| Joe Perches | 226afe6 | 2010-12-02 19:12:37 -0800 | [diff] [blame] | 288 | 	ath_dbg(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", | 
 | 289 | 		name, nbuf, ndesc); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 290 |  | 
 | 291 | 	INIT_LIST_HEAD(head); | 
| Vasanthakumar Thiagarajan | 4adfcde | 2010-04-15 17:39:33 -0400 | [diff] [blame] | 292 |  | 
 | 293 | 	if (is_tx) | 
 | 294 | 		desc_len = sc->sc_ah->caps.tx_desc_len; | 
 | 295 | 	else | 
 | 296 | 		desc_len = sizeof(struct ath_desc); | 
 | 297 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 298 | 	/* ath_desc must be a multiple of DWORDs */ | 
| Vasanthakumar Thiagarajan | 4adfcde | 2010-04-15 17:39:33 -0400 | [diff] [blame] | 299 | 	if ((desc_len % 4) != 0) { | 
| Joe Perches | 3800276 | 2010-12-02 19:12:36 -0800 | [diff] [blame] | 300 | 		ath_err(common, "ath_desc not DWORD aligned\n"); | 
| Vasanthakumar Thiagarajan | 4adfcde | 2010-04-15 17:39:33 -0400 | [diff] [blame] | 301 | 		BUG_ON((desc_len % 4) != 0); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 302 | 		error = -ENOMEM; | 
 | 303 | 		goto fail; | 
 | 304 | 	} | 
 | 305 |  | 
| Vasanthakumar Thiagarajan | 4adfcde | 2010-04-15 17:39:33 -0400 | [diff] [blame] | 306 | 	dd->dd_desc_len = desc_len * nbuf * ndesc; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 307 |  | 
 | 308 | 	/* | 
 | 309 | 	 * Need additional DMA memory because we can't use | 
 | 310 | 	 * descriptors that cross the 4K page boundary. Assume | 
 | 311 | 	 * one skipped descriptor per 4K page. | 
 | 312 | 	 */ | 
 | 313 | 	if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { | 
 | 314 | 		u32 ndesc_skipped = | 
 | 315 | 			ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); | 
 | 316 | 		u32 dma_len; | 
 | 317 |  | 
 | 318 | 		while (ndesc_skipped) { | 
| Vasanthakumar Thiagarajan | 4adfcde | 2010-04-15 17:39:33 -0400 | [diff] [blame] | 319 | 			dma_len = ndesc_skipped * desc_len; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 320 | 			dd->dd_desc_len += dma_len; | 
 | 321 |  | 
 | 322 | 			ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); | 
| Joe Perches | ee289b6 | 2010-05-17 22:47:34 -0700 | [diff] [blame] | 323 | 		} | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 324 | 	} | 
 | 325 |  | 
 | 326 | 	/* allocate descriptors */ | 
 | 327 | 	dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, | 
 | 328 | 					 &dd->dd_desc_paddr, GFP_KERNEL); | 
 | 329 | 	if (dd->dd_desc == NULL) { | 
 | 330 | 		error = -ENOMEM; | 
 | 331 | 		goto fail; | 
 | 332 | 	} | 
| Vasanthakumar Thiagarajan | 4adfcde | 2010-04-15 17:39:33 -0400 | [diff] [blame] | 333 | 	ds = (u8 *) dd->dd_desc; | 
| Joe Perches | 226afe6 | 2010-12-02 19:12:37 -0800 | [diff] [blame] | 334 | 	ath_dbg(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", | 
 | 335 | 		name, ds, (u32) dd->dd_desc_len, | 
 | 336 | 		ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 337 |  | 
 | 338 | 	/* allocate buffers */ | 
 | 339 | 	bsize = sizeof(struct ath_buf) * nbuf; | 
 | 340 | 	bf = kzalloc(bsize, GFP_KERNEL); | 
 | 341 | 	if (bf == NULL) { | 
 | 342 | 		error = -ENOMEM; | 
 | 343 | 		goto fail2; | 
 | 344 | 	} | 
 | 345 | 	dd->dd_bufptr = bf; | 
 | 346 |  | 
| Vasanthakumar Thiagarajan | 4adfcde | 2010-04-15 17:39:33 -0400 | [diff] [blame] | 347 | 	for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 348 | 		bf->bf_desc = ds; | 
 | 349 | 		bf->bf_daddr = DS2PHYS(dd, ds); | 
 | 350 |  | 
 | 351 | 		if (!(sc->sc_ah->caps.hw_caps & | 
 | 352 | 		      ATH9K_HW_CAP_4KB_SPLITTRANS)) { | 
 | 353 | 			/* | 
 | 354 | 			 * Skip descriptor addresses which can cause 4KB | 
 | 355 | 			 * boundary crossing (addr + length) with a 32 dword | 
 | 356 | 			 * descriptor fetch. | 
 | 357 | 			 */ | 
 | 358 | 			while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { | 
 | 359 | 				BUG_ON((caddr_t) bf->bf_desc >= | 
 | 360 | 				       ((caddr_t) dd->dd_desc + | 
 | 361 | 					dd->dd_desc_len)); | 
 | 362 |  | 
| Vasanthakumar Thiagarajan | 4adfcde | 2010-04-15 17:39:33 -0400 | [diff] [blame] | 363 | 				ds += (desc_len * ndesc); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 364 | 				bf->bf_desc = ds; | 
 | 365 | 				bf->bf_daddr = DS2PHYS(dd, ds); | 
 | 366 | 			} | 
 | 367 | 		} | 
 | 368 | 		list_add_tail(&bf->list, head); | 
 | 369 | 	} | 
 | 370 | 	return 0; | 
 | 371 | fail2: | 
 | 372 | 	dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, | 
 | 373 | 			  dd->dd_desc_paddr); | 
 | 374 | fail: | 
 | 375 | 	memset(dd, 0, sizeof(*dd)); | 
 | 376 | 	return error; | 
 | 377 | #undef ATH_DESC_4KB_BOUND_CHECK | 
 | 378 | #undef ATH_DESC_4KB_BOUND_NUM_SKIPPED | 
 | 379 | #undef DS2PHYS | 
 | 380 | } | 
 | 381 |  | 
| Mohammed Shafi Shajakhan | db7ec38 | 2010-12-22 12:20:12 +0530 | [diff] [blame] | 382 | void ath9k_init_crypto(struct ath_softc *sc) | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 383 | { | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 384 | 	struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 
 | 385 | 	int i = 0; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 386 |  | 
 | 387 | 	/* Get the hardware key cache size. */ | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 388 | 	common->keymax = sc->sc_ah->caps.keycache_size; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 389 | 	if (common->keymax > ATH_KEYMAX) { | 
| Joe Perches | 226afe6 | 2010-12-02 19:12:37 -0800 | [diff] [blame] | 390 | 		ath_dbg(common, ATH_DBG_ANY, | 
 | 391 | 			"Warning, using only %u entries in %u key cache\n", | 
 | 392 | 			ATH_KEYMAX, common->keymax); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 393 | 		common->keymax = ATH_KEYMAX; | 
 | 394 | 	} | 
 | 395 |  | 
 | 396 | 	/* | 
 | 397 | 	 * Reset the key cache since some parts do not | 
 | 398 | 	 * reset the contents on initial power up. | 
 | 399 | 	 */ | 
 | 400 | 	for (i = 0; i < common->keymax; i++) | 
| Bruno Randolf | 040e539 | 2010-09-08 16:05:04 +0900 | [diff] [blame] | 401 | 		ath_hw_keyreset(common, (u16) i); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 402 |  | 
| Felix Fietkau | 716f7fc | 2010-06-12 17:22:28 +0200 | [diff] [blame] | 403 | 	/* | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 404 | 	 * Check whether the separate key cache entries | 
 | 405 | 	 * are required to handle both tx+rx MIC keys. | 
 | 406 | 	 * With split mic keys the number of stations is limited | 
 | 407 | 	 * to 27 otherwise 59. | 
 | 408 | 	 */ | 
| Bruno Randolf | 117675d | 2010-09-08 16:04:54 +0900 | [diff] [blame] | 409 | 	if (sc->sc_ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) | 
 | 410 | 		common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 411 | } | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 412 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 413 | static int ath9k_init_btcoex(struct ath_softc *sc) | 
 | 414 | { | 
| Felix Fietkau | 066dae9 | 2010-11-07 14:59:39 +0100 | [diff] [blame] | 415 | 	struct ath_txq *txq; | 
 | 416 | 	int r; | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 417 |  | 
 | 418 | 	switch (sc->sc_ah->btcoex_hw.scheme) { | 
 | 419 | 	case ATH_BTCOEX_CFG_NONE: | 
 | 420 | 		break; | 
 | 421 | 	case ATH_BTCOEX_CFG_2WIRE: | 
 | 422 | 		ath9k_hw_btcoex_init_2wire(sc->sc_ah); | 
 | 423 | 		break; | 
 | 424 | 	case ATH_BTCOEX_CFG_3WIRE: | 
 | 425 | 		ath9k_hw_btcoex_init_3wire(sc->sc_ah); | 
 | 426 | 		r = ath_init_btcoex_timer(sc); | 
 | 427 | 		if (r) | 
 | 428 | 			return -1; | 
| Felix Fietkau | 066dae9 | 2010-11-07 14:59:39 +0100 | [diff] [blame] | 429 | 		txq = sc->tx.txq_map[WME_AC_BE]; | 
 | 430 | 		ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 431 | 		sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; | 
 | 432 | 		break; | 
 | 433 | 	default: | 
 | 434 | 		WARN_ON(1); | 
 | 435 | 		break; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 436 | 	} | 
 | 437 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 438 | 	return 0; | 
 | 439 | } | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 440 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 441 | static int ath9k_init_queues(struct ath_softc *sc) | 
 | 442 | { | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 443 | 	int i = 0; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 444 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 445 | 	sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah); | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 446 | 	sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 447 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 448 | 	sc->config.cabqReadytime = ATH_CABQ_READY_TIME; | 
 | 449 | 	ath_cabq_update(sc); | 
 | 450 |  | 
| Ben Greear | 60f2d1d | 2011-01-09 23:11:52 -0800 | [diff] [blame] | 451 | 	for (i = 0; i < WME_NUM_AC; i++) { | 
| Felix Fietkau | 066dae9 | 2010-11-07 14:59:39 +0100 | [diff] [blame] | 452 | 		sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i); | 
| Ben Greear | 60f2d1d | 2011-01-09 23:11:52 -0800 | [diff] [blame] | 453 | 		sc->tx.txq_map[i]->mac80211_qnum = i; | 
 | 454 | 	} | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 455 | 	return 0; | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 456 | } | 
 | 457 |  | 
| Felix Fietkau | f209f52 | 2010-10-01 01:06:53 +0200 | [diff] [blame] | 458 | static int ath9k_init_channels_rates(struct ath_softc *sc) | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 459 | { | 
| Felix Fietkau | f209f52 | 2010-10-01 01:06:53 +0200 | [diff] [blame] | 460 | 	void *channels; | 
 | 461 |  | 
| Felix Fietkau | cac4220 | 2010-10-09 02:39:30 +0200 | [diff] [blame] | 462 | 	BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + | 
 | 463 | 		     ARRAY_SIZE(ath9k_5ghz_chantable) != | 
 | 464 | 		     ATH9K_NUM_CHANNELS); | 
 | 465 |  | 
| Felix Fietkau | d465991 | 2010-10-14 16:02:39 +0200 | [diff] [blame] | 466 | 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { | 
| Felix Fietkau | f209f52 | 2010-10-01 01:06:53 +0200 | [diff] [blame] | 467 | 		channels = kmemdup(ath9k_2ghz_chantable, | 
 | 468 | 			sizeof(ath9k_2ghz_chantable), GFP_KERNEL); | 
 | 469 | 		if (!channels) | 
 | 470 | 		    return -ENOMEM; | 
 | 471 |  | 
 | 472 | 		sc->sbands[IEEE80211_BAND_2GHZ].channels = channels; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 473 | 		sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; | 
 | 474 | 		sc->sbands[IEEE80211_BAND_2GHZ].n_channels = | 
 | 475 | 			ARRAY_SIZE(ath9k_2ghz_chantable); | 
 | 476 | 		sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; | 
 | 477 | 		sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = | 
 | 478 | 			ARRAY_SIZE(ath9k_legacy_rates); | 
 | 479 | 	} | 
 | 480 |  | 
| Felix Fietkau | d465991 | 2010-10-14 16:02:39 +0200 | [diff] [blame] | 481 | 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { | 
| Felix Fietkau | f209f52 | 2010-10-01 01:06:53 +0200 | [diff] [blame] | 482 | 		channels = kmemdup(ath9k_5ghz_chantable, | 
 | 483 | 			sizeof(ath9k_5ghz_chantable), GFP_KERNEL); | 
 | 484 | 		if (!channels) { | 
 | 485 | 			if (sc->sbands[IEEE80211_BAND_2GHZ].channels) | 
 | 486 | 				kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels); | 
 | 487 | 			return -ENOMEM; | 
 | 488 | 		} | 
 | 489 |  | 
 | 490 | 		sc->sbands[IEEE80211_BAND_5GHZ].channels = channels; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 491 | 		sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; | 
 | 492 | 		sc->sbands[IEEE80211_BAND_5GHZ].n_channels = | 
 | 493 | 			ARRAY_SIZE(ath9k_5ghz_chantable); | 
 | 494 | 		sc->sbands[IEEE80211_BAND_5GHZ].bitrates = | 
 | 495 | 			ath9k_legacy_rates + 4; | 
 | 496 | 		sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = | 
 | 497 | 			ARRAY_SIZE(ath9k_legacy_rates) - 4; | 
 | 498 | 	} | 
| Felix Fietkau | f209f52 | 2010-10-01 01:06:53 +0200 | [diff] [blame] | 499 | 	return 0; | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 500 | } | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 501 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 502 | static void ath9k_init_misc(struct ath_softc *sc) | 
 | 503 | { | 
 | 504 | 	struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 
 | 505 | 	int i = 0; | 
 | 506 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 507 | 	setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); | 
 | 508 |  | 
 | 509 | 	sc->config.txpowlimit = ATH_TXPOWER_MAX; | 
 | 510 |  | 
 | 511 | 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { | 
 | 512 | 		sc->sc_flags |= SC_OP_TXAGGR; | 
 | 513 | 		sc->sc_flags |= SC_OP_RXAGGR; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 514 | 	} | 
 | 515 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 516 | 	common->tx_chainmask = sc->sc_ah->caps.tx_chainmask; | 
 | 517 | 	common->rx_chainmask = sc->sc_ah->caps.rx_chainmask; | 
 | 518 |  | 
| Luis R. Rodriguez | 8fe6536 | 2010-04-15 17:38:14 -0400 | [diff] [blame] | 519 | 	ath9k_hw_set_diversity(sc->sc_ah, true); | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 520 | 	sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah); | 
 | 521 |  | 
| Felix Fietkau | 364734f | 2010-09-14 20:22:44 +0200 | [diff] [blame] | 522 | 	memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 523 |  | 
 | 524 | 	sc->beacon.slottime = ATH9K_SLOT_TIME_9; | 
 | 525 |  | 
| Felix Fietkau | 7545daf | 2011-01-24 19:23:16 +0100 | [diff] [blame] | 526 | 	for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 527 | 		sc->beacon.bslot[i] = NULL; | 
| Vasanthakumar Thiagarajan | 102885a | 2010-09-02 01:34:43 -0700 | [diff] [blame] | 528 |  | 
 | 529 | 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) | 
 | 530 | 		sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 531 | } | 
 | 532 |  | 
 | 533 | static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, | 
 | 534 | 			    const struct ath_bus_ops *bus_ops) | 
 | 535 | { | 
| Felix Fietkau | 6fb1b1e | 2011-03-19 13:55:39 +0100 | [diff] [blame] | 536 | 	struct ath9k_platform_data *pdata = sc->dev->platform_data; | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 537 | 	struct ath_hw *ah = NULL; | 
 | 538 | 	struct ath_common *common; | 
 | 539 | 	int ret = 0, i; | 
 | 540 | 	int csz = 0; | 
 | 541 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 542 | 	ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); | 
 | 543 | 	if (!ah) | 
 | 544 | 		return -ENOMEM; | 
 | 545 |  | 
| Ben Greear | 233536e | 2011-01-09 23:11:44 -0800 | [diff] [blame] | 546 | 	ah->hw = sc->hw; | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 547 | 	ah->hw_version.devid = devid; | 
 | 548 | 	ah->hw_version.subsysid = subsysid; | 
| Felix Fietkau | f9f84e9 | 2011-03-23 20:57:24 +0100 | [diff] [blame^] | 549 | 	ah->reg_ops.read = ath9k_ioread32; | 
 | 550 | 	ah->reg_ops.write = ath9k_iowrite32; | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 551 | 	sc->sc_ah = ah; | 
 | 552 |  | 
| Felix Fietkau | 6de66dd | 2011-03-19 13:55:40 +0100 | [diff] [blame] | 553 | 	if (!pdata) { | 
| Felix Fietkau | a05b5d45 | 2010-11-17 04:25:33 +0100 | [diff] [blame] | 554 | 		ah->ah_flags |= AH_USE_EEPROM; | 
| Felix Fietkau | 6de66dd | 2011-03-19 13:55:40 +0100 | [diff] [blame] | 555 | 		sc->sc_ah->led_pin = -1; | 
 | 556 | 	} else { | 
 | 557 | 		sc->sc_ah->gpio_mask = pdata->gpio_mask; | 
 | 558 | 		sc->sc_ah->gpio_val = pdata->gpio_val; | 
 | 559 | 		sc->sc_ah->led_pin = pdata->led_pin; | 
 | 560 | 	} | 
| Felix Fietkau | a05b5d45 | 2010-11-17 04:25:33 +0100 | [diff] [blame] | 561 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 562 | 	common = ath9k_hw_common(ah); | 
| Felix Fietkau | f9f84e9 | 2011-03-23 20:57:24 +0100 | [diff] [blame^] | 563 | 	common->ops = &ah->reg_ops; | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 564 | 	common->bus_ops = bus_ops; | 
 | 565 | 	common->ah = ah; | 
 | 566 | 	common->hw = sc->hw; | 
 | 567 | 	common->priv = sc; | 
 | 568 | 	common->debug_mask = ath9k_debug; | 
| Vasanthakumar Thiagarajan | 8f5dcb1 | 2010-11-26 06:10:06 -0800 | [diff] [blame] | 569 | 	common->btcoex_enabled = ath9k_btcoex_enable == 1; | 
| Ben Greear | 20b25744 | 2010-10-15 15:04:09 -0700 | [diff] [blame] | 570 | 	spin_lock_init(&common->cc_lock); | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 571 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 572 | 	spin_lock_init(&sc->sc_serial_rw); | 
 | 573 | 	spin_lock_init(&sc->sc_pm_lock); | 
 | 574 | 	mutex_init(&sc->mutex); | 
| Ben Greear | 7f010c9 | 2011-01-09 23:11:49 -0800 | [diff] [blame] | 575 | #ifdef CONFIG_ATH9K_DEBUGFS | 
 | 576 | 	spin_lock_init(&sc->nodes_lock); | 
 | 577 | 	INIT_LIST_HEAD(&sc->nodes); | 
 | 578 | #endif | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 579 | 	tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); | 
 | 580 | 	tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, | 
 | 581 | 		     (unsigned long)sc); | 
 | 582 |  | 
 | 583 | 	/* | 
 | 584 | 	 * Cache line size is used to size and align various | 
 | 585 | 	 * structures used to communicate with the hardware. | 
 | 586 | 	 */ | 
 | 587 | 	ath_read_cachesize(common, &csz); | 
 | 588 | 	common->cachelsz = csz << 2; /* convert to bytes */ | 
 | 589 |  | 
| Luis R. Rodriguez | d70357d | 2010-04-15 17:38:06 -0400 | [diff] [blame] | 590 | 	/* Initializes the hardware for all supported chipsets */ | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 591 | 	ret = ath9k_hw_init(ah); | 
| Luis R. Rodriguez | d70357d | 2010-04-15 17:38:06 -0400 | [diff] [blame] | 592 | 	if (ret) | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 593 | 		goto err_hw; | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 594 |  | 
| Felix Fietkau | 6fb1b1e | 2011-03-19 13:55:39 +0100 | [diff] [blame] | 595 | 	if (pdata && pdata->macaddr) | 
 | 596 | 		memcpy(common->macaddr, pdata->macaddr, ETH_ALEN); | 
 | 597 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 598 | 	ret = ath9k_init_queues(sc); | 
 | 599 | 	if (ret) | 
 | 600 | 		goto err_queues; | 
 | 601 |  | 
 | 602 | 	ret =  ath9k_init_btcoex(sc); | 
 | 603 | 	if (ret) | 
 | 604 | 		goto err_btcoex; | 
 | 605 |  | 
| Felix Fietkau | f209f52 | 2010-10-01 01:06:53 +0200 | [diff] [blame] | 606 | 	ret = ath9k_init_channels_rates(sc); | 
 | 607 | 	if (ret) | 
 | 608 | 		goto err_btcoex; | 
 | 609 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 610 | 	ath9k_init_crypto(sc); | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 611 | 	ath9k_init_misc(sc); | 
 | 612 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 613 | 	return 0; | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 614 |  | 
 | 615 | err_btcoex: | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 616 | 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | 
 | 617 | 		if (ATH_TXQ_SETUP(sc, i)) | 
 | 618 | 			ath_tx_cleanupq(sc, &sc->tx.txq[i]); | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 619 | err_queues: | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 620 | 	ath9k_hw_deinit(ah); | 
 | 621 | err_hw: | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 622 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 623 | 	kfree(ah); | 
 | 624 | 	sc->sc_ah = NULL; | 
 | 625 |  | 
 | 626 | 	return ret; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 627 | } | 
 | 628 |  | 
| Felix Fietkau | babcbc2 | 2010-10-20 02:09:46 +0200 | [diff] [blame] | 629 | static void ath9k_init_band_txpower(struct ath_softc *sc, int band) | 
 | 630 | { | 
 | 631 | 	struct ieee80211_supported_band *sband; | 
 | 632 | 	struct ieee80211_channel *chan; | 
 | 633 | 	struct ath_hw *ah = sc->sc_ah; | 
 | 634 | 	struct ath_regulatory *reg = ath9k_hw_regulatory(ah); | 
 | 635 | 	int i; | 
 | 636 |  | 
 | 637 | 	sband = &sc->sbands[band]; | 
 | 638 | 	for (i = 0; i < sband->n_channels; i++) { | 
 | 639 | 		chan = &sband->channels[i]; | 
 | 640 | 		ah->curchan = &ah->channels[chan->hw_value]; | 
 | 641 | 		ath9k_cmn_update_ichannel(ah->curchan, chan, NL80211_CHAN_HT20); | 
 | 642 | 		ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true); | 
 | 643 | 		chan->max_power = reg->max_power_level / 2; | 
 | 644 | 	} | 
 | 645 | } | 
 | 646 |  | 
 | 647 | static void ath9k_init_txpower_limits(struct ath_softc *sc) | 
 | 648 | { | 
 | 649 | 	struct ath_hw *ah = sc->sc_ah; | 
 | 650 | 	struct ath9k_channel *curchan = ah->curchan; | 
 | 651 |  | 
 | 652 | 	if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) | 
 | 653 | 		ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ); | 
 | 654 | 	if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) | 
 | 655 | 		ath9k_init_band_txpower(sc, IEEE80211_BAND_5GHZ); | 
 | 656 |  | 
 | 657 | 	ah->curchan = curchan; | 
 | 658 | } | 
 | 659 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 660 | void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 661 | { | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 662 | 	struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 
 | 663 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 664 | 	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | | 
 | 665 | 		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 
 | 666 | 		IEEE80211_HW_SIGNAL_DBM | | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 667 | 		IEEE80211_HW_SUPPORTS_PS | | 
 | 668 | 		IEEE80211_HW_PS_NULLFUNC_STACK | | 
| Vivek Natarajan | 05df498 | 2010-02-09 11:34:50 +0530 | [diff] [blame] | 669 | 		IEEE80211_HW_SPECTRUM_MGMT | | 
| Mohammed Shafi Shajakhan | bd8027a | 2010-12-30 12:18:01 +0530 | [diff] [blame] | 670 | 		IEEE80211_HW_REPORTS_TX_ACK_STATUS; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 671 |  | 
| Luis R. Rodriguez | 5ffaf8a | 2010-02-02 11:58:33 -0500 | [diff] [blame] | 672 | 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) | 
 | 673 | 		 hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; | 
 | 674 |  | 
| John W. Linville | 3e6109c | 2011-01-05 09:39:17 -0500 | [diff] [blame] | 675 | 	if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 676 | 		hw->flags |= IEEE80211_HW_MFP_CAPABLE; | 
 | 677 |  | 
 | 678 | 	hw->wiphy->interface_modes = | 
| Johannes Berg | c426ee2 | 2010-11-26 11:38:04 +0100 | [diff] [blame] | 679 | 		BIT(NL80211_IFTYPE_P2P_GO) | | 
 | 680 | 		BIT(NL80211_IFTYPE_P2P_CLIENT) | | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 681 | 		BIT(NL80211_IFTYPE_AP) | | 
| Bill Jordan | e51f3ef | 2010-10-01 11:20:39 -0400 | [diff] [blame] | 682 | 		BIT(NL80211_IFTYPE_WDS) | | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 683 | 		BIT(NL80211_IFTYPE_STATION) | | 
 | 684 | 		BIT(NL80211_IFTYPE_ADHOC) | | 
 | 685 | 		BIT(NL80211_IFTYPE_MESH_POINT); | 
 | 686 |  | 
| Luis R. Rodriguez | 008443d | 2010-09-16 15:12:36 -0400 | [diff] [blame] | 687 | 	if (AR_SREV_5416(sc->sc_ah)) | 
 | 688 | 		hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 689 |  | 
| Jouni Malinen | cfdc9a8 | 2011-03-23 14:52:19 +0200 | [diff] [blame] | 690 | 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | 
 | 691 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 692 | 	hw->queues = 4; | 
 | 693 | 	hw->max_rates = 4; | 
 | 694 | 	hw->channel_change_time = 5000; | 
 | 695 | 	hw->max_listen_interval = 10; | 
| Felix Fietkau | 6589651 | 2010-01-24 03:26:11 +0100 | [diff] [blame] | 696 | 	hw->max_rate_tries = 10; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 697 | 	hw->sta_data_size = sizeof(struct ath_node); | 
 | 698 | 	hw->vif_data_size = sizeof(struct ath_vif); | 
 | 699 |  | 
| Felix Fietkau | 6e5c2b4 | 2010-09-20 13:45:40 +0200 | [diff] [blame] | 700 | #ifdef CONFIG_ATH9K_RATE_CONTROL | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 701 | 	hw->rate_control_algorithm = "ath9k_rate_control"; | 
| Felix Fietkau | 6e5c2b4 | 2010-09-20 13:45:40 +0200 | [diff] [blame] | 702 | #endif | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 703 |  | 
| Felix Fietkau | d465991 | 2010-10-14 16:02:39 +0200 | [diff] [blame] | 704 | 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 705 | 		hw->wiphy->bands[IEEE80211_BAND_2GHZ] = | 
 | 706 | 			&sc->sbands[IEEE80211_BAND_2GHZ]; | 
| Felix Fietkau | d465991 | 2010-10-14 16:02:39 +0200 | [diff] [blame] | 707 | 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 708 | 		hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | 
 | 709 | 			&sc->sbands[IEEE80211_BAND_5GHZ]; | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 710 |  | 
 | 711 | 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { | 
| Felix Fietkau | d465991 | 2010-10-14 16:02:39 +0200 | [diff] [blame] | 712 | 		if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 713 | 			setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); | 
| Felix Fietkau | d465991 | 2010-10-14 16:02:39 +0200 | [diff] [blame] | 714 | 		if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 715 | 			setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); | 
 | 716 | 	} | 
 | 717 |  | 
 | 718 | 	SET_IEEE80211_PERM_ADDR(hw, common->macaddr); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 719 | } | 
 | 720 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 721 | int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 722 | 		    const struct ath_bus_ops *bus_ops) | 
 | 723 | { | 
 | 724 | 	struct ieee80211_hw *hw = sc->hw; | 
 | 725 | 	struct ath_common *common; | 
 | 726 | 	struct ath_hw *ah; | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 727 | 	int error = 0; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 728 | 	struct ath_regulatory *reg; | 
 | 729 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 730 | 	/* Bring up device */ | 
 | 731 | 	error = ath9k_init_softc(devid, sc, subsysid, bus_ops); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 732 | 	if (error != 0) | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 733 | 		goto error_init; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 734 |  | 
 | 735 | 	ah = sc->sc_ah; | 
 | 736 | 	common = ath9k_hw_common(ah); | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 737 | 	ath9k_set_hw_capab(sc, hw); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 738 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 739 | 	/* Initialize regulatory */ | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 740 | 	error = ath_regd_init(&common->regulatory, sc->hw->wiphy, | 
 | 741 | 			      ath9k_reg_notifier); | 
 | 742 | 	if (error) | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 743 | 		goto error_regd; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 744 |  | 
 | 745 | 	reg = &common->regulatory; | 
 | 746 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 747 | 	/* Setup TX DMA */ | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 748 | 	error = ath_tx_init(sc, ATH_TXBUF); | 
 | 749 | 	if (error != 0) | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 750 | 		goto error_tx; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 751 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 752 | 	/* Setup RX DMA */ | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 753 | 	error = ath_rx_init(sc, ATH_RXBUF); | 
 | 754 | 	if (error != 0) | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 755 | 		goto error_rx; | 
 | 756 |  | 
| Felix Fietkau | babcbc2 | 2010-10-20 02:09:46 +0200 | [diff] [blame] | 757 | 	ath9k_init_txpower_limits(sc); | 
 | 758 |  | 
| Felix Fietkau | 0cf55c2 | 2011-02-27 22:26:40 +0100 | [diff] [blame] | 759 | #ifdef CONFIG_MAC80211_LEDS | 
 | 760 | 	/* must be initialized before ieee80211_register_hw */ | 
 | 761 | 	sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw, | 
 | 762 | 		IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink, | 
 | 763 | 		ARRAY_SIZE(ath9k_tpt_blink)); | 
 | 764 | #endif | 
 | 765 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 766 | 	/* Register with mac80211 */ | 
 | 767 | 	error = ieee80211_register_hw(hw); | 
 | 768 | 	if (error) | 
 | 769 | 		goto error_register; | 
 | 770 |  | 
| Ben Greear | eb27244 | 2010-11-29 14:13:22 -0800 | [diff] [blame] | 771 | 	error = ath9k_init_debug(ah); | 
 | 772 | 	if (error) { | 
| Joe Perches | 3800276 | 2010-12-02 19:12:36 -0800 | [diff] [blame] | 773 | 		ath_err(common, "Unable to create debugfs files\n"); | 
| Ben Greear | eb27244 | 2010-11-29 14:13:22 -0800 | [diff] [blame] | 774 | 		goto error_world; | 
 | 775 | 	} | 
 | 776 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 777 | 	/* Handle world regulatory */ | 
 | 778 | 	if (!ath_is_world_regd(reg)) { | 
 | 779 | 		error = regulatory_hint(hw->wiphy, reg->alpha2); | 
 | 780 | 		if (error) | 
 | 781 | 			goto error_world; | 
 | 782 | 	} | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 783 |  | 
| Felix Fietkau | 347809f | 2010-07-02 00:09:52 +0200 | [diff] [blame] | 784 | 	INIT_WORK(&sc->hw_check_work, ath_hw_check); | 
| Felix Fietkau | 9f42c2b | 2010-06-12 00:34:01 -0400 | [diff] [blame] | 785 | 	INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); | 
| Felix Fietkau | 9ac58615 | 2011-01-24 19:23:18 +0100 | [diff] [blame] | 786 | 	sc->last_rssi = ATH_RSSI_DUMMY_MARKER; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 787 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 788 | 	ath_init_leds(sc); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 789 | 	ath_start_rfkill_poll(sc); | 
 | 790 |  | 
 | 791 | 	return 0; | 
 | 792 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 793 | error_world: | 
 | 794 | 	ieee80211_unregister_hw(hw); | 
 | 795 | error_register: | 
 | 796 | 	ath_rx_cleanup(sc); | 
 | 797 | error_rx: | 
 | 798 | 	ath_tx_cleanup(sc); | 
 | 799 | error_tx: | 
 | 800 | 	/* Nothing */ | 
 | 801 | error_regd: | 
 | 802 | 	ath9k_deinit_softc(sc); | 
 | 803 | error_init: | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 804 | 	return error; | 
 | 805 | } | 
 | 806 |  | 
 | 807 | /*****************************/ | 
 | 808 | /*     De-Initialization     */ | 
 | 809 | /*****************************/ | 
 | 810 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 811 | static void ath9k_deinit_softc(struct ath_softc *sc) | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 812 | { | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 813 | 	int i = 0; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 814 |  | 
| Felix Fietkau | f209f52 | 2010-10-01 01:06:53 +0200 | [diff] [blame] | 815 | 	if (sc->sbands[IEEE80211_BAND_2GHZ].channels) | 
 | 816 | 		kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels); | 
 | 817 |  | 
 | 818 | 	if (sc->sbands[IEEE80211_BAND_5GHZ].channels) | 
 | 819 | 		kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels); | 
 | 820 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 821 |         if ((sc->btcoex.no_stomp_timer) && | 
 | 822 | 	    sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) | 
 | 823 | 		ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 824 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 825 | 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | 
 | 826 | 		if (ATH_TXQ_SETUP(sc, i)) | 
 | 827 | 			ath_tx_cleanupq(sc, &sc->tx.txq[i]); | 
 | 828 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 829 | 	ath9k_hw_deinit(sc->sc_ah); | 
 | 830 |  | 
| Sujith | 736b3a2 | 2010-03-17 14:25:24 +0530 | [diff] [blame] | 831 | 	kfree(sc->sc_ah); | 
 | 832 | 	sc->sc_ah = NULL; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 833 | } | 
 | 834 |  | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 835 | void ath9k_deinit_device(struct ath_softc *sc) | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 836 | { | 
 | 837 | 	struct ieee80211_hw *hw = sc->hw; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 838 |  | 
 | 839 | 	ath9k_ps_wakeup(sc); | 
 | 840 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 841 | 	wiphy_rfkill_stop_polling(sc->hw->wiphy); | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 842 | 	ath_deinit_leds(sc); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 843 |  | 
| Rajkumar Manoharan | c7c1806 | 2011-01-27 18:39:38 +0530 | [diff] [blame] | 844 | 	ath9k_ps_restore(sc); | 
 | 845 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 846 | 	ieee80211_unregister_hw(hw); | 
 | 847 | 	ath_rx_cleanup(sc); | 
 | 848 | 	ath_tx_cleanup(sc); | 
| Sujith | 285f2dd | 2010-01-08 10:36:07 +0530 | [diff] [blame] | 849 | 	ath9k_deinit_softc(sc); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 850 | } | 
 | 851 |  | 
 | 852 | void ath_descdma_cleanup(struct ath_softc *sc, | 
 | 853 | 			 struct ath_descdma *dd, | 
 | 854 | 			 struct list_head *head) | 
 | 855 | { | 
 | 856 | 	dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, | 
 | 857 | 			  dd->dd_desc_paddr); | 
 | 858 |  | 
 | 859 | 	INIT_LIST_HEAD(head); | 
 | 860 | 	kfree(dd->dd_bufptr); | 
 | 861 | 	memset(dd, 0, sizeof(*dd)); | 
 | 862 | } | 
 | 863 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 864 | /************************/ | 
 | 865 | /*     Module Hooks     */ | 
 | 866 | /************************/ | 
 | 867 |  | 
 | 868 | static int __init ath9k_init(void) | 
 | 869 | { | 
 | 870 | 	int error; | 
 | 871 |  | 
 | 872 | 	/* Register rate control algorithm */ | 
 | 873 | 	error = ath_rate_control_register(); | 
 | 874 | 	if (error != 0) { | 
 | 875 | 		printk(KERN_ERR | 
 | 876 | 			"ath9k: Unable to register rate control " | 
 | 877 | 			"algorithm: %d\n", | 
 | 878 | 			error); | 
 | 879 | 		goto err_out; | 
 | 880 | 	} | 
 | 881 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 882 | 	error = ath_pci_init(); | 
 | 883 | 	if (error < 0) { | 
 | 884 | 		printk(KERN_ERR | 
 | 885 | 			"ath9k: No PCI devices found, driver not installed.\n"); | 
 | 886 | 		error = -ENODEV; | 
| Ben Greear | eb27244 | 2010-11-29 14:13:22 -0800 | [diff] [blame] | 887 | 		goto err_rate_unregister; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 888 | 	} | 
 | 889 |  | 
 | 890 | 	error = ath_ahb_init(); | 
 | 891 | 	if (error < 0) { | 
 | 892 | 		error = -ENODEV; | 
 | 893 | 		goto err_pci_exit; | 
 | 894 | 	} | 
 | 895 |  | 
 | 896 | 	return 0; | 
 | 897 |  | 
 | 898 |  err_pci_exit: | 
 | 899 | 	ath_pci_exit(); | 
 | 900 |  | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 901 |  err_rate_unregister: | 
 | 902 | 	ath_rate_control_unregister(); | 
 | 903 |  err_out: | 
 | 904 | 	return error; | 
 | 905 | } | 
 | 906 | module_init(ath9k_init); | 
 | 907 |  | 
 | 908 | static void __exit ath9k_exit(void) | 
 | 909 | { | 
| Rajkumar Manoharan | d584747 | 2010-12-20 14:39:51 +0530 | [diff] [blame] | 910 | 	is_ath9k_unloaded = true; | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 911 | 	ath_ahb_exit(); | 
 | 912 | 	ath_pci_exit(); | 
| Sujith | 5562420 | 2010-01-08 10:36:02 +0530 | [diff] [blame] | 913 | 	ath_rate_control_unregister(); | 
 | 914 | 	printk(KERN_INFO "%s: Driver unloaded\n", dev_info); | 
 | 915 | } | 
 | 916 | module_exit(ath9k_exit); |