Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
attach.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2004-2008 Reyk Floeter <[email protected]>
3  * Copyright (c) 2006-2008 Nick Kossifidis <[email protected]>
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 
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 
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  */
117  ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
118  ah->ah_imr = 0;
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 */
140 
141  /* Fill the ath5k_hw struct with the needed functions */
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;
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;
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;
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 ||
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;
208  } else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) ||
209  ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
211  ah->ah_radio = AR5K_RF2425;
212  ah->ah_single_chip = true;
214  } else if (srev == AR5K_SREV_AR5213A &&
216  ah->ah_radio = AR5K_RF5112;
217  ah->ah_single_chip = false;
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;
224  } else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) ||
226  ah->ah_radio = AR5K_RF5413;
227  ah->ah_single_chip = true;
229  } else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) ||
231  ah->ah_radio = AR5K_RF2413;
232  ah->ah_single_chip = true;
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)
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 ?
314 
315  if (srev >= AR5K_SREV_AR5212_V4 &&
319 
320  if (srev >= AR5K_SREV_AR2414) {
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  memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN);
331  ath5k_hw_set_bssid(ah);
332  ath5k_hw_set_opmode(ah, ah->opmode);
333 
335 
337 
338  /* turn on HW LEDs */
340 
341  return 0;
342 err:
343  return ret;
344 }
345 
351 {
352  __set_bit(ATH_STAT_INVALID, ah->status);
353 
354  if (ah->ah_rf_banks != NULL)
355  kfree(ah->ah_rf_banks);
356 
358 
359  /* assume interrupts are down */
360 }