Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
0003  * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
0004  *
0005  * Permission to use, copy, modify, and distribute this software for any
0006  * purpose with or without fee is hereby granted, provided that the above
0007  * copyright notice and this permission notice appear in all copies.
0008  *
0009  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0010  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0011  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0012  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0013  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0014  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0015  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0016  *
0017  */
0018 
0019 /*************************************\
0020 * Attach/Detach Functions and helpers *
0021 \*************************************/
0022 
0023 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0024 
0025 #include <linux/pci.h>
0026 #include <linux/slab.h>
0027 #include "ath5k.h"
0028 #include "reg.h"
0029 #include "debug.h"
0030 
0031 /**
0032  * ath5k_hw_post() - Power On Self Test helper function
0033  * @ah: The &struct ath5k_hw
0034  */
0035 static int ath5k_hw_post(struct ath5k_hw *ah)
0036 {
0037 
0038     static const u32 static_pattern[4] = {
0039         0x55555555, 0xaaaaaaaa,
0040         0x66666666, 0x99999999
0041     };
0042     static const u16 regs[2] = { AR5K_STA_ID0, AR5K_PHY(8) };
0043     int i, c;
0044     u16 cur_reg;
0045     u32 var_pattern;
0046     u32 init_val;
0047     u32 cur_val;
0048 
0049     for (c = 0; c < 2; c++) {
0050 
0051         cur_reg = regs[c];
0052 
0053         /* Save previous value */
0054         init_val = ath5k_hw_reg_read(ah, cur_reg);
0055 
0056         for (i = 0; i < 256; i++) {
0057             var_pattern = i << 16 | i;
0058             ath5k_hw_reg_write(ah, var_pattern, cur_reg);
0059             cur_val = ath5k_hw_reg_read(ah, cur_reg);
0060 
0061             if (cur_val != var_pattern) {
0062                 ATH5K_ERR(ah, "POST Failed !!!\n");
0063                 return -EAGAIN;
0064             }
0065 
0066             /* Found on ndiswrapper dumps */
0067             var_pattern = 0x0039080f;
0068             ath5k_hw_reg_write(ah, var_pattern, cur_reg);
0069         }
0070 
0071         for (i = 0; i < 4; i++) {
0072             var_pattern = static_pattern[i];
0073             ath5k_hw_reg_write(ah, var_pattern, cur_reg);
0074             cur_val = ath5k_hw_reg_read(ah, cur_reg);
0075 
0076             if (cur_val != var_pattern) {
0077                 ATH5K_ERR(ah, "POST Failed !!!\n");
0078                 return -EAGAIN;
0079             }
0080 
0081             /* Found on ndiswrapper dumps */
0082             var_pattern = 0x003b080f;
0083             ath5k_hw_reg_write(ah, var_pattern, cur_reg);
0084         }
0085 
0086         /* Restore previous value */
0087         ath5k_hw_reg_write(ah, init_val, cur_reg);
0088 
0089     }
0090 
0091     return 0;
0092 
0093 }
0094 
0095 /**
0096  * ath5k_hw_init() - Check if hw is supported and init the needed structs
0097  * @ah: The &struct ath5k_hw associated with the device
0098  *
0099  * Check if the device is supported, perform a POST and initialize the needed
0100  * structs. Returns -ENOMEM if we don't have memory for the needed structs,
0101  * -ENODEV if the device is not supported or prints an error msg if something
0102  * else went wrong.
0103  */
0104 int ath5k_hw_init(struct ath5k_hw *ah)
0105 {
0106     static const u8 zero_mac[ETH_ALEN] = { };
0107     struct ath_common *common = ath5k_hw_common(ah);
0108     struct pci_dev *pdev = ah->pdev;
0109     struct ath5k_eeprom_info *ee;
0110     int ret;
0111     u32 srev;
0112 
0113     /*
0114      * HW information
0115      */
0116     ah->ah_bwmode = AR5K_BWMODE_DEFAULT;
0117     ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
0118     ah->ah_imr = 0;
0119     ah->ah_retry_short = AR5K_INIT_RETRY_SHORT;
0120     ah->ah_retry_long = AR5K_INIT_RETRY_LONG;
0121     ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT;
0122     ah->ah_noise_floor = -95;   /* until first NF calibration is run */
0123     ah->ani_state.ani_mode = ATH5K_ANI_MODE_AUTO;
0124     ah->ah_current_channel = &ah->channels[0];
0125 
0126     /*
0127      * Find the mac version
0128      */
0129     ath5k_hw_read_srev(ah);
0130     srev = ah->ah_mac_srev;
0131     if (srev < AR5K_SREV_AR5311)
0132         ah->ah_version = AR5K_AR5210;
0133     else if (srev < AR5K_SREV_AR5212)
0134         ah->ah_version = AR5K_AR5211;
0135     else
0136         ah->ah_version = AR5K_AR5212;
0137 
0138     /* Get the MAC version */
0139     ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
0140 
0141     /* Fill the ath5k_hw struct with the needed functions */
0142     ret = ath5k_hw_init_desc_functions(ah);
0143     if (ret)
0144         goto err;
0145 
0146     /* Bring device out of sleep and reset its units */
0147     ret = ath5k_hw_nic_wakeup(ah, NULL);
0148     if (ret)
0149         goto err;
0150 
0151     /* Get PHY and RADIO revisions */
0152     ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
0153             0xffffffff;
0154     ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
0155             NL80211_BAND_5GHZ);
0156 
0157     /* Try to identify radio chip based on its srev */
0158     switch (ah->ah_radio_5ghz_revision & 0xf0) {
0159     case AR5K_SREV_RAD_5111:
0160         ah->ah_radio = AR5K_RF5111;
0161         ah->ah_single_chip = false;
0162         ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
0163                             NL80211_BAND_2GHZ);
0164         break;
0165     case AR5K_SREV_RAD_5112:
0166     case AR5K_SREV_RAD_2112:
0167         ah->ah_radio = AR5K_RF5112;
0168         ah->ah_single_chip = false;
0169         ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
0170                             NL80211_BAND_2GHZ);
0171         break;
0172     case AR5K_SREV_RAD_2413:
0173         ah->ah_radio = AR5K_RF2413;
0174         ah->ah_single_chip = true;
0175         break;
0176     case AR5K_SREV_RAD_5413:
0177         ah->ah_radio = AR5K_RF5413;
0178         ah->ah_single_chip = true;
0179         break;
0180     case AR5K_SREV_RAD_2316:
0181         ah->ah_radio = AR5K_RF2316;
0182         ah->ah_single_chip = true;
0183         break;
0184     case AR5K_SREV_RAD_2317:
0185         ah->ah_radio = AR5K_RF2317;
0186         ah->ah_single_chip = true;
0187         break;
0188     case AR5K_SREV_RAD_5424:
0189         if (ah->ah_mac_version == AR5K_SREV_AR2425 ||
0190             ah->ah_mac_version == AR5K_SREV_AR2417) {
0191             ah->ah_radio = AR5K_RF2425;
0192             ah->ah_single_chip = true;
0193         } else {
0194             ah->ah_radio = AR5K_RF5413;
0195             ah->ah_single_chip = true;
0196         }
0197         break;
0198     default:
0199         /* Identify radio based on mac/phy srev */
0200         if (ah->ah_version == AR5K_AR5210) {
0201             ah->ah_radio = AR5K_RF5110;
0202             ah->ah_single_chip = false;
0203         } else if (ah->ah_version == AR5K_AR5211) {
0204             ah->ah_radio = AR5K_RF5111;
0205             ah->ah_single_chip = false;
0206             ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
0207                             NL80211_BAND_2GHZ);
0208         } else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) ||
0209                ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
0210                ah->ah_phy_revision == AR5K_SREV_PHY_2425) {
0211             ah->ah_radio = AR5K_RF2425;
0212             ah->ah_single_chip = true;
0213             ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425;
0214         } else if (srev == AR5K_SREV_AR5213A &&
0215                ah->ah_phy_revision == AR5K_SREV_PHY_5212B) {
0216             ah->ah_radio = AR5K_RF5112;
0217             ah->ah_single_chip = false;
0218             ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B;
0219         } else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4) ||
0220                ah->ah_mac_version == (AR5K_SREV_AR2315_R6 >> 4)) {
0221             ah->ah_radio = AR5K_RF2316;
0222             ah->ah_single_chip = true;
0223             ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316;
0224         } else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) ||
0225                ah->ah_phy_revision == AR5K_SREV_PHY_5413) {
0226             ah->ah_radio = AR5K_RF5413;
0227             ah->ah_single_chip = true;
0228             ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413;
0229         } else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) ||
0230                ah->ah_phy_revision == AR5K_SREV_PHY_2413) {
0231             ah->ah_radio = AR5K_RF2413;
0232             ah->ah_single_chip = true;
0233             ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413;
0234         } else {
0235             ATH5K_ERR(ah, "Couldn't identify radio revision.\n");
0236             ret = -ENODEV;
0237             goto err;
0238         }
0239     }
0240 
0241 
0242     /* Return on unsupported chips (unsupported eeprom etc) */
0243     if ((srev >= AR5K_SREV_AR5416) && (srev < AR5K_SREV_AR2425)) {
0244         ATH5K_ERR(ah, "Device not yet supported.\n");
0245         ret = -ENODEV;
0246         goto err;
0247     }
0248 
0249     /*
0250      * POST
0251      */
0252     ret = ath5k_hw_post(ah);
0253     if (ret)
0254         goto err;
0255 
0256     /* Enable pci core retry fix on Hainan (5213A) and later chips */
0257     if (srev >= AR5K_SREV_AR5213A)
0258         AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_RETRY_FIX);
0259 
0260     /*
0261      * Get card capabilities, calibration values etc
0262      * TODO: EEPROM work
0263      */
0264     ret = ath5k_eeprom_init(ah);
0265     if (ret) {
0266         ATH5K_ERR(ah, "unable to init EEPROM\n");
0267         goto err;
0268     }
0269 
0270     ee = &ah->ah_capabilities.cap_eeprom;
0271 
0272     /*
0273      * Write PCI-E power save settings
0274      */
0275     if ((ah->ah_version == AR5K_AR5212) && pdev && (pci_is_pcie(pdev))) {
0276         ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
0277         ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
0278 
0279         /* Shut off RX when elecidle is asserted */
0280         ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
0281         ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
0282 
0283         /* If serdes programming is enabled, increase PCI-E
0284          * tx power for systems with long trace from host
0285          * to minicard connector. */
0286         if (ee->ee_serdes)
0287             ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
0288         else
0289             ath5k_hw_reg_write(ah, 0xf6800579, AR5K_PCIE_SERDES);
0290 
0291         /* Shut off PLL and CLKREQ active in L1 */
0292         ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
0293 
0294         /* Preserve other settings */
0295         ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
0296         ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
0297         ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
0298 
0299         /* Reset SERDES to load new settings */
0300         ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
0301         usleep_range(1000, 1500);
0302     }
0303 
0304     /* Get misc capabilities */
0305     ret = ath5k_hw_set_capabilities(ah);
0306     if (ret) {
0307         ATH5K_ERR(ah, "unable to get device capabilities\n");
0308         goto err;
0309     }
0310 
0311     /* Crypto settings */
0312     common->keymax = (ah->ah_version == AR5K_AR5210 ?
0313               AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211);
0314 
0315     if (srev >= AR5K_SREV_AR5212_V4 &&
0316         (ee->ee_version < AR5K_EEPROM_VERSION_5_0 ||
0317         !AR5K_EEPROM_AES_DIS(ee->ee_misc5)))
0318         common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
0319 
0320     if (srev >= AR5K_SREV_AR2414) {
0321         common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
0322         AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE,
0323             AR5K_MISC_MODE_COMBINED_MIC);
0324     }
0325 
0326     /* MAC address is cleared until add_interface */
0327     ath5k_hw_set_lladdr(ah, zero_mac);
0328 
0329     /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
0330     eth_broadcast_addr(common->curbssid);
0331     ath5k_hw_set_bssid(ah);
0332     ath5k_hw_set_opmode(ah, ah->opmode);
0333 
0334     ath5k_hw_rfgain_opt_init(ah);
0335 
0336     ath5k_hw_init_nfcal_hist(ah);
0337 
0338     /* turn on HW LEDs */
0339     ath5k_hw_set_ledstate(ah, AR5K_LED_INIT);
0340 
0341     return 0;
0342 err:
0343     return ret;
0344 }
0345 
0346 /**
0347  * ath5k_hw_deinit() - Free the &struct ath5k_hw
0348  * @ah: The &struct ath5k_hw
0349  */
0350 void ath5k_hw_deinit(struct ath5k_hw *ah)
0351 {
0352     __set_bit(ATH_STAT_INVALID, ah->status);
0353 
0354     kfree(ah->ah_rf_banks);
0355 
0356     ath5k_eeprom_detach(ah);
0357 
0358     /* assume interrupts are down */
0359 }