root/drivers/net/wireless/ath/ath5k/attach.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ath5k_hw_post
  2. ath5k_hw_init
  3. ath5k_hw_deinit

   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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  24 
  25 #include <linux/pci.h>
  26 #include <linux/slab.h>
  27 #include "ath5k.h"
  28 #include "reg.h"
  29 #include "debug.h"
  30 
  31 /**
  32  * ath5k_hw_post() - Power On Self Test helper function
  33  * @ah: The &struct ath5k_hw
  34  */
  35 static int ath5k_hw_post(struct ath5k_hw *ah)
  36 {
  37 
  38         static const u32 static_pattern[4] = {
  39                 0x55555555,     0xaaaaaaaa,
  40                 0x66666666,     0x99999999
  41         };
  42         static const u16 regs[2] = { AR5K_STA_ID0, AR5K_PHY(8) };
  43         int i, c;
  44         u16 cur_reg;
  45         u32 var_pattern;
  46         u32 init_val;
  47         u32 cur_val;
  48 
  49         for (c = 0; c < 2; c++) {
  50 
  51                 cur_reg = regs[c];
  52 
  53                 /* Save previous value */
  54                 init_val = ath5k_hw_reg_read(ah, cur_reg);
  55 
  56                 for (i = 0; i < 256; i++) {
  57                         var_pattern = i << 16 | i;
  58                         ath5k_hw_reg_write(ah, var_pattern, cur_reg);
  59                         cur_val = ath5k_hw_reg_read(ah, cur_reg);
  60 
  61                         if (cur_val != var_pattern) {
  62                                 ATH5K_ERR(ah, "POST Failed !!!\n");
  63                                 return -EAGAIN;
  64                         }
  65 
  66                         /* Found on ndiswrapper dumps */
  67                         var_pattern = 0x0039080f;
  68                         ath5k_hw_reg_write(ah, var_pattern, cur_reg);
  69                 }
  70 
  71                 for (i = 0; i < 4; i++) {
  72                         var_pattern = static_pattern[i];
  73                         ath5k_hw_reg_write(ah, var_pattern, cur_reg);
  74                         cur_val = ath5k_hw_reg_read(ah, cur_reg);
  75 
  76                         if (cur_val != var_pattern) {
  77                                 ATH5K_ERR(ah, "POST Failed !!!\n");
  78                                 return -EAGAIN;
  79                         }
  80 
  81                         /* Found on ndiswrapper dumps */
  82                         var_pattern = 0x003b080f;
  83                         ath5k_hw_reg_write(ah, var_pattern, cur_reg);
  84                 }
  85 
  86                 /* Restore previous value */
  87                 ath5k_hw_reg_write(ah, init_val, cur_reg);
  88 
  89         }
  90 
  91         return 0;
  92 
  93 }
  94 
  95 /**
  96  * ath5k_hw_init() - Check if hw is supported and init the needed structs
  97  * @ah: The &struct ath5k_hw associated with the device
  98  *
  99  * Check if the device is supported, perform a POST and initialize the needed
 100  * structs. Returns -ENOMEM if we don't have memory for the needed structs,
 101  * -ENODEV if the device is not supported or prints an error msg if something
 102  * else went wrong.
 103  */
 104 int ath5k_hw_init(struct ath5k_hw *ah)
 105 {
 106         static const u8 zero_mac[ETH_ALEN] = { };
 107         struct ath_common *common = ath5k_hw_common(ah);
 108         struct pci_dev *pdev = ah->pdev;
 109         struct ath5k_eeprom_info *ee;
 110         int ret;
 111         u32 srev;
 112 
 113         /*
 114          * HW information
 115          */
 116         ah->ah_bwmode = AR5K_BWMODE_DEFAULT;
 117         ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
 118         ah->ah_imr = 0;
 119         ah->ah_retry_short = AR5K_INIT_RETRY_SHORT;
 120         ah->ah_retry_long = AR5K_INIT_RETRY_LONG;
 121         ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT;
 122         ah->ah_noise_floor = -95;       /* until first NF calibration is run */
 123         ah->ani_state.ani_mode = ATH5K_ANI_MODE_AUTO;
 124         ah->ah_current_channel = &ah->channels[0];
 125 
 126         /*
 127          * Find the mac version
 128          */
 129         ath5k_hw_read_srev(ah);
 130         srev = ah->ah_mac_srev;
 131         if (srev < AR5K_SREV_AR5311)
 132                 ah->ah_version = AR5K_AR5210;
 133         else if (srev < AR5K_SREV_AR5212)
 134                 ah->ah_version = AR5K_AR5211;
 135         else
 136                 ah->ah_version = AR5K_AR5212;
 137 
 138         /* Get the MAC version */
 139         ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
 140 
 141         /* Fill the ath5k_hw struct with the needed functions */
 142         ret = ath5k_hw_init_desc_functions(ah);
 143         if (ret)
 144                 goto err;
 145 
 146         /* Bring device out of sleep and reset its units */
 147         ret = ath5k_hw_nic_wakeup(ah, NULL);
 148         if (ret)
 149                 goto err;
 150 
 151         /* Get PHY and RADIO revisions */
 152         ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
 153                         0xffffffff;
 154         ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
 155                         NL80211_BAND_5GHZ);
 156 
 157         /* Try to identify radio chip based on its srev */
 158         switch (ah->ah_radio_5ghz_revision & 0xf0) {
 159         case AR5K_SREV_RAD_5111:
 160                 ah->ah_radio = AR5K_RF5111;
 161                 ah->ah_single_chip = false;
 162                 ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
 163                                                         NL80211_BAND_2GHZ);
 164                 break;
 165         case AR5K_SREV_RAD_5112:
 166         case AR5K_SREV_RAD_2112:
 167                 ah->ah_radio = AR5K_RF5112;
 168                 ah->ah_single_chip = false;
 169                 ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
 170                                                         NL80211_BAND_2GHZ);
 171                 break;
 172         case AR5K_SREV_RAD_2413:
 173                 ah->ah_radio = AR5K_RF2413;
 174                 ah->ah_single_chip = true;
 175                 break;
 176         case AR5K_SREV_RAD_5413:
 177                 ah->ah_radio = AR5K_RF5413;
 178                 ah->ah_single_chip = true;
 179                 break;
 180         case AR5K_SREV_RAD_2316:
 181                 ah->ah_radio = AR5K_RF2316;
 182                 ah->ah_single_chip = true;
 183                 break;
 184         case AR5K_SREV_RAD_2317:
 185                 ah->ah_radio = AR5K_RF2317;
 186                 ah->ah_single_chip = true;
 187                 break;
 188         case AR5K_SREV_RAD_5424:
 189                 if (ah->ah_mac_version == AR5K_SREV_AR2425 ||
 190                     ah->ah_mac_version == AR5K_SREV_AR2417) {
 191                         ah->ah_radio = AR5K_RF2425;
 192                         ah->ah_single_chip = true;
 193                 } else {
 194                         ah->ah_radio = AR5K_RF5413;
 195                         ah->ah_single_chip = true;
 196                 }
 197                 break;
 198         default:
 199                 /* Identify radio based on mac/phy srev */
 200                 if (ah->ah_version == AR5K_AR5210) {
 201                         ah->ah_radio = AR5K_RF5110;
 202                         ah->ah_single_chip = false;
 203                 } else if (ah->ah_version == AR5K_AR5211) {
 204                         ah->ah_radio = AR5K_RF5111;
 205                         ah->ah_single_chip = false;
 206                         ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
 207                                                         NL80211_BAND_2GHZ);
 208                 } else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) ||
 209                            ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
 210                            ah->ah_phy_revision == AR5K_SREV_PHY_2425) {
 211                         ah->ah_radio = AR5K_RF2425;
 212                         ah->ah_single_chip = true;
 213                         ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425;
 214                 } else if (srev == AR5K_SREV_AR5213A &&
 215                            ah->ah_phy_revision == AR5K_SREV_PHY_5212B) {
 216                         ah->ah_radio = AR5K_RF5112;
 217                         ah->ah_single_chip = false;
 218                         ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B;
 219                 } else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4) ||
 220                            ah->ah_mac_version == (AR5K_SREV_AR2315_R6 >> 4)) {
 221                         ah->ah_radio = AR5K_RF2316;
 222                         ah->ah_single_chip = true;
 223                         ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316;
 224                 } else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) ||
 225                            ah->ah_phy_revision == AR5K_SREV_PHY_5413) {
 226                         ah->ah_radio = AR5K_RF5413;
 227                         ah->ah_single_chip = true;
 228                         ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413;
 229                 } else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) ||
 230                            ah->ah_phy_revision == AR5K_SREV_PHY_2413) {
 231                         ah->ah_radio = AR5K_RF2413;
 232                         ah->ah_single_chip = true;
 233                         ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413;
 234                 } else {
 235                         ATH5K_ERR(ah, "Couldn't identify radio revision.\n");
 236                         ret = -ENODEV;
 237                         goto err;
 238                 }
 239         }
 240 
 241 
 242         /* Return on unsupported chips (unsupported eeprom etc) */
 243         if ((srev >= AR5K_SREV_AR5416) && (srev < AR5K_SREV_AR2425)) {
 244                 ATH5K_ERR(ah, "Device not yet supported.\n");
 245                 ret = -ENODEV;
 246                 goto err;
 247         }
 248 
 249         /*
 250          * POST
 251          */
 252         ret = ath5k_hw_post(ah);
 253         if (ret)
 254                 goto err;
 255 
 256         /* Enable pci core retry fix on Hainan (5213A) and later chips */
 257         if (srev >= AR5K_SREV_AR5213A)
 258                 AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_RETRY_FIX);
 259 
 260         /*
 261          * Get card capabilities, calibration values etc
 262          * TODO: EEPROM work
 263          */
 264         ret = ath5k_eeprom_init(ah);
 265         if (ret) {
 266                 ATH5K_ERR(ah, "unable to init EEPROM\n");
 267                 goto err;
 268         }
 269 
 270         ee = &ah->ah_capabilities.cap_eeprom;
 271 
 272         /*
 273          * Write PCI-E power save settings
 274          */
 275         if ((ah->ah_version == AR5K_AR5212) && pdev && (pci_is_pcie(pdev))) {
 276                 ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
 277                 ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
 278 
 279                 /* Shut off RX when elecidle is asserted */
 280                 ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
 281                 ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
 282 
 283                 /* If serdes programming is enabled, increase PCI-E
 284                  * tx power for systems with long trace from host
 285                  * to minicard connector. */
 286                 if (ee->ee_serdes)
 287                         ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
 288                 else
 289                         ath5k_hw_reg_write(ah, 0xf6800579, AR5K_PCIE_SERDES);
 290 
 291                 /* Shut off PLL and CLKREQ active in L1 */
 292                 ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
 293 
 294                 /* Preserve other settings */
 295                 ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
 296                 ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
 297                 ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
 298 
 299                 /* Reset SERDES to load new settings */
 300                 ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
 301                 usleep_range(1000, 1500);
 302         }
 303 
 304         /* Get misc capabilities */
 305         ret = ath5k_hw_set_capabilities(ah);
 306         if (ret) {
 307                 ATH5K_ERR(ah, "unable to get device capabilities\n");
 308                 goto err;
 309         }
 310 
 311         /* Crypto settings */
 312         common->keymax = (ah->ah_version == AR5K_AR5210 ?
 313                           AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211);
 314 
 315         if (srev >= AR5K_SREV_AR5212_V4 &&
 316             (ee->ee_version < AR5K_EEPROM_VERSION_5_0 ||
 317             !AR5K_EEPROM_AES_DIS(ee->ee_misc5)))
 318                 common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
 319 
 320         if (srev >= AR5K_SREV_AR2414) {
 321                 common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
 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, zero_mac);
 328 
 329         /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
 330         eth_broadcast_addr(common->curbssid);
 331         ath5k_hw_set_bssid(ah);
 332         ath5k_hw_set_opmode(ah, ah->opmode);
 333 
 334         ath5k_hw_rfgain_opt_init(ah);
 335 
 336         ath5k_hw_init_nfcal_hist(ah);
 337 
 338         /* turn on HW LEDs */
 339         ath5k_hw_set_ledstate(ah, AR5K_LED_INIT);
 340 
 341         return 0;
 342 err:
 343         return ret;
 344 }
 345 
 346 /**
 347  * ath5k_hw_deinit() - Free the &struct ath5k_hw
 348  * @ah: The &struct ath5k_hw
 349  */
 350 void ath5k_hw_deinit(struct ath5k_hw *ah)
 351 {
 352         __set_bit(ATH_STAT_INVALID, ah->status);
 353 
 354         kfree(ah->ah_rf_banks);
 355 
 356         ath5k_eeprom_detach(ah);
 357 
 358         /* assume interrupts are down */
 359 }

/* [<][>][^][v][top][bottom][index][help] */