Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.29 359 lines 10 kB view raw
1/* 2 * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> 3 * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 */ 18 19/*************************************\ 20* Attach/Detach Functions and helpers * 21\*************************************/ 22 23#include <linux/pci.h> 24#include "ath5k.h" 25#include "reg.h" 26#include "debug.h" 27#include "base.h" 28 29/** 30 * ath5k_hw_post - Power On Self Test helper function 31 * 32 * @ah: The &struct ath5k_hw 33 */ 34static int ath5k_hw_post(struct ath5k_hw *ah) 35{ 36 37 int i, c; 38 u16 cur_reg; 39 u16 regs[2] = {AR5K_STA_ID0, AR5K_PHY(8)}; 40 u32 var_pattern; 41 u32 static_pattern[4] = { 42 0x55555555, 0xaaaaaaaa, 43 0x66666666, 0x99999999 44 }; 45 u32 init_val; 46 u32 cur_val; 47 48 for (c = 0; c < 2; c++) { 49 50 cur_reg = regs[c]; 51 52 /* Save previous value */ 53 init_val = ath5k_hw_reg_read(ah, cur_reg); 54 55 for (i = 0; i < 256; i++) { 56 var_pattern = i << 16 | i; 57 ath5k_hw_reg_write(ah, var_pattern, cur_reg); 58 cur_val = ath5k_hw_reg_read(ah, cur_reg); 59 60 if (cur_val != var_pattern) { 61 ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); 62 return -EAGAIN; 63 } 64 65 /* Found on ndiswrapper dumps */ 66 var_pattern = 0x0039080f; 67 ath5k_hw_reg_write(ah, var_pattern, cur_reg); 68 } 69 70 for (i = 0; i < 4; i++) { 71 var_pattern = static_pattern[i]; 72 ath5k_hw_reg_write(ah, var_pattern, cur_reg); 73 cur_val = ath5k_hw_reg_read(ah, cur_reg); 74 75 if (cur_val != var_pattern) { 76 ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); 77 return -EAGAIN; 78 } 79 80 /* Found on ndiswrapper dumps */ 81 var_pattern = 0x003b080f; 82 ath5k_hw_reg_write(ah, var_pattern, cur_reg); 83 } 84 85 /* Restore previous value */ 86 ath5k_hw_reg_write(ah, init_val, cur_reg); 87 88 } 89 90 return 0; 91 92} 93 94/** 95 * ath5k_hw_attach - Check if hw is supported and init the needed structs 96 * 97 * @sc: The &struct ath5k_softc we got from the driver's attach function 98 * @mac_version: The mac version id (check out ath5k.h) based on pci id 99 * 100 * Check if the device is supported, perform a POST and initialize the needed 101 * structs. Returns -ENOMEM if we don't have memory for the needed structs, 102 * -ENODEV if the device is not supported or prints an error msg if something 103 * else went wrong. 104 */ 105struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) 106{ 107 struct ath5k_hw *ah; 108 struct pci_dev *pdev = sc->pdev; 109 u8 mac[ETH_ALEN] = {}; 110 int ret; 111 u32 srev; 112 113 /*If we passed the test malloc a ath5k_hw struct*/ 114 ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL); 115 if (ah == NULL) { 116 ret = -ENOMEM; 117 ATH5K_ERR(sc, "out of memory\n"); 118 goto err; 119 } 120 121 ah->ah_sc = sc; 122 ah->ah_iobase = sc->iobase; 123 124 /* 125 * HW information 126 */ 127 ah->ah_op_mode = NL80211_IFTYPE_STATION; 128 ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT; 129 ah->ah_turbo = false; 130 ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; 131 ah->ah_imr = 0; 132 ah->ah_atim_window = 0; 133 ah->ah_aifs = AR5K_TUNE_AIFS; 134 ah->ah_cw_min = AR5K_TUNE_CWMIN; 135 ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; 136 ah->ah_software_retry = false; 137 ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY; 138 139 /* 140 * Set the mac version based on the pci id 141 */ 142 ah->ah_version = mac_version; 143 144 /*Fill the ath5k_hw struct with the needed functions*/ 145 ret = ath5k_hw_init_desc_functions(ah); 146 if (ret) 147 goto err_free; 148 149 /* Bring device out of sleep and reset it's units */ 150 ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true); 151 if (ret) 152 goto err_free; 153 154 /* Get MAC, PHY and RADIO revisions */ 155 srev = ath5k_hw_reg_read(ah, AR5K_SREV); 156 ah->ah_mac_srev = srev; 157 ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER); 158 ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV); 159 ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) & 160 0xffffffff; 161 ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, 162 CHANNEL_5GHZ); 163 ah->ah_phy = AR5K_PHY(0); 164 165 /* Try to identify radio chip based on it's srev */ 166 switch (ah->ah_radio_5ghz_revision & 0xf0) { 167 case AR5K_SREV_RAD_5111: 168 ah->ah_radio = AR5K_RF5111; 169 ah->ah_single_chip = false; 170 ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, 171 CHANNEL_2GHZ); 172 ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111; 173 break; 174 case AR5K_SREV_RAD_5112: 175 case AR5K_SREV_RAD_2112: 176 ah->ah_radio = AR5K_RF5112; 177 ah->ah_single_chip = false; 178 ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, 179 CHANNEL_2GHZ); 180 ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112; 181 break; 182 case AR5K_SREV_RAD_2413: 183 ah->ah_radio = AR5K_RF2413; 184 ah->ah_single_chip = true; 185 ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; 186 break; 187 case AR5K_SREV_RAD_5413: 188 ah->ah_radio = AR5K_RF5413; 189 ah->ah_single_chip = true; 190 ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; 191 break; 192 case AR5K_SREV_RAD_2316: 193 ah->ah_radio = AR5K_RF2316; 194 ah->ah_single_chip = true; 195 ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316; 196 break; 197 case AR5K_SREV_RAD_2317: 198 ah->ah_radio = AR5K_RF2317; 199 ah->ah_single_chip = true; 200 ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2317; 201 break; 202 case AR5K_SREV_RAD_5424: 203 if (ah->ah_mac_version == AR5K_SREV_AR2425 || 204 ah->ah_mac_version == AR5K_SREV_AR2417){ 205 ah->ah_radio = AR5K_RF2425; 206 ah->ah_single_chip = true; 207 ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425; 208 } else { 209 ah->ah_radio = AR5K_RF5413; 210 ah->ah_single_chip = true; 211 ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; 212 } 213 break; 214 default: 215 /* Identify radio based on mac/phy srev */ 216 if (ah->ah_version == AR5K_AR5210) { 217 ah->ah_radio = AR5K_RF5110; 218 ah->ah_single_chip = false; 219 } else if (ah->ah_version == AR5K_AR5211) { 220 ah->ah_radio = AR5K_RF5111; 221 ah->ah_single_chip = false; 222 ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, 223 CHANNEL_2GHZ); 224 } else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) || 225 ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) || 226 ah->ah_phy_revision == AR5K_SREV_PHY_2425) { 227 ah->ah_radio = AR5K_RF2425; 228 ah->ah_single_chip = true; 229 ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425; 230 ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425; 231 } else if (srev == AR5K_SREV_AR5213A && 232 ah->ah_phy_revision == AR5K_SREV_PHY_2112B) { 233 ah->ah_radio = AR5K_RF5112; 234 ah->ah_single_chip = false; 235 ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2112B; 236 } else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4)) { 237 ah->ah_radio = AR5K_RF2316; 238 ah->ah_single_chip = true; 239 ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316; 240 ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2316; 241 } else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) || 242 ah->ah_phy_revision == AR5K_SREV_PHY_5413) { 243 ah->ah_radio = AR5K_RF5413; 244 ah->ah_single_chip = true; 245 ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413; 246 ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413; 247 } else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) || 248 ah->ah_phy_revision == AR5K_SREV_PHY_2413) { 249 ah->ah_radio = AR5K_RF2413; 250 ah->ah_single_chip = true; 251 ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413; 252 ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413; 253 } else { 254 ATH5K_ERR(sc, "Couldn't identify radio revision.\n"); 255 ret = -ENODEV; 256 goto err_free; 257 } 258 } 259 260 261 /* Return on unsuported chips (unsupported eeprom etc) */ 262 if ((srev >= AR5K_SREV_AR5416) && 263 (srev < AR5K_SREV_AR2425)) { 264 ATH5K_ERR(sc, "Device not yet supported.\n"); 265 ret = -ENODEV; 266 goto err_free; 267 } 268 269 /* 270 * Write PCI-E power save settings 271 */ 272 if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { 273 ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES); 274 ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES); 275 /* Shut off RX when elecidle is asserted */ 276 ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES); 277 ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES); 278 /* TODO: EEPROM work */ 279 ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES); 280 /* Shut off PLL and CLKREQ active in L1 */ 281 ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES); 282 /* Preserce other settings */ 283 ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES); 284 ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES); 285 ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES); 286 /* Reset SERDES to load new settings */ 287 ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET); 288 mdelay(1); 289 } 290 291 /* 292 * POST 293 */ 294 ret = ath5k_hw_post(ah); 295 if (ret) 296 goto err_free; 297 298 /* Enable pci core retry fix on Hainan (5213A) and later chips */ 299 if (srev >= AR5K_SREV_AR5213A) 300 ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG); 301 302 /* 303 * Get card capabilities, calibration values etc 304 * TODO: EEPROM work 305 */ 306 ret = ath5k_eeprom_init(ah); 307 if (ret) { 308 ATH5K_ERR(sc, "unable to init EEPROM\n"); 309 goto err_free; 310 } 311 312 /* Get misc capabilities */ 313 ret = ath5k_hw_set_capabilities(ah); 314 if (ret) { 315 ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n", 316 sc->pdev->device); 317 goto err_free; 318 } 319 320 if (srev >= AR5K_SREV_AR2414) { 321 ah->ah_combined_mic = true; 322 AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE, 323 AR5K_MISC_MODE_COMBINED_MIC); 324 } 325 326 /* MAC address is cleared until add_interface */ 327 ath5k_hw_set_lladdr(ah, mac); 328 329 /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ 330 memset(ah->ah_bssid, 0xff, ETH_ALEN); 331 ath5k_hw_set_associd(ah, ah->ah_bssid, 0); 332 ath5k_hw_set_opmode(ah); 333 334 ath5k_hw_set_rfgain_opt(ah); 335 336 return ah; 337err_free: 338 kfree(ah); 339err: 340 return ERR_PTR(ret); 341} 342 343/** 344 * ath5k_hw_detach - Free the ath5k_hw struct 345 * 346 * @ah: The &struct ath5k_hw 347 */ 348void ath5k_hw_detach(struct ath5k_hw *ah) 349{ 350 ATH5K_TRACE(ah->ah_sc); 351 352 __set_bit(ATH_STAT_INVALID, ah->ah_sc->status); 353 354 if (ah->ah_rf_banks != NULL) 355 kfree(ah->ah_rf_banks); 356 357 /* assume interrupts are down */ 358 kfree(ah); 359}