iPXE
ath5k_attach.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
3  * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
4  *
5  * Modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>
6  * Original from Linux kernel 2.6.30.
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  *
20  */
21 
22 FILE_LICENCE ( MIT );
23 
24 /*************************************\
25 * Attach/Detach Functions and helpers *
26 \*************************************/
27 
28 #include <ipxe/pci.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include "ath5k.h"
32 #include "reg.h"
33 #include "base.h"
34 
35 /**
36  * ath5k_hw_post - Power On Self Test helper function
37  *
38  * @ah: The &struct ath5k_hw
39  */
40 static int ath5k_hw_post(struct ath5k_hw *ah)
41 {
42 
43  static const u32 static_pattern[4] = {
44  0x55555555, 0xaaaaaaaa,
45  0x66666666, 0x99999999
46  };
47  static const u16 regs[2] = { AR5K_STA_ID0, AR5K_PHY(8) };
48  int i, c;
49  u16 cur_reg;
50  u32 var_pattern;
51  u32 init_val;
52  u32 cur_val;
53 
54  for (c = 0; c < 2; c++) {
55 
56  cur_reg = regs[c];
57 
58  /* Save previous value */
59  init_val = ath5k_hw_reg_read(ah, cur_reg);
60 
61  for (i = 0; i < 256; i++) {
62  var_pattern = i << 16 | i;
63  ath5k_hw_reg_write(ah, var_pattern, cur_reg);
64  cur_val = ath5k_hw_reg_read(ah, cur_reg);
65 
66  if (cur_val != var_pattern) {
67  DBG("ath5k: POST failed!\n");
68  return -EAGAIN;
69  }
70 
71  /* Found on ndiswrapper dumps */
72  var_pattern = 0x0039080f;
73  ath5k_hw_reg_write(ah, var_pattern, cur_reg);
74  }
75 
76  for (i = 0; i < 4; i++) {
77  var_pattern = static_pattern[i];
78  ath5k_hw_reg_write(ah, var_pattern, cur_reg);
79  cur_val = ath5k_hw_reg_read(ah, cur_reg);
80 
81  if (cur_val != var_pattern) {
82  DBG("ath5k: POST failed!\n");
83  return -EAGAIN;
84  }
85 
86  /* Found on ndiswrapper dumps */
87  var_pattern = 0x003b080f;
88  ath5k_hw_reg_write(ah, var_pattern, cur_reg);
89  }
90 
91  /* Restore previous value */
92  ath5k_hw_reg_write(ah, init_val, cur_reg);
93 
94  }
95 
96  return 0;
97 
98 }
99 
100 /**
101  * ath5k_hw_attach - Check if hw is supported and init the needed structs
102  *
103  * @sc: The &struct ath5k_softc we got from the driver's attach function
104  * @mac_version: The mac version id (check out ath5k.h) based on pci id
105  * @hw: Returned newly allocated hardware structure, on success
106  *
107  * Check if the device is supported, perform a POST and initialize the needed
108  * structs. Returns -ENOMEM if we don't have memory for the needed structs,
109  * -ENODEV if the device is not supported or prints an error msg if something
110  * else went wrong.
111  */
112 int ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version,
113  struct ath5k_hw **hw)
114 {
115  struct ath5k_hw *ah;
116  struct pci_device *pdev = sc->pdev;
117  int ret;
118  u32 srev;
119 
120  ah = zalloc(sizeof(struct ath5k_hw));
121  if (ah == NULL) {
122  ret = -ENOMEM;
123  DBG("ath5k: out of memory\n");
124  goto err;
125  }
126 
127  ah->ah_sc = sc;
128  ah->ah_iobase = sc->iobase;
129 
130  /*
131  * HW information
132  */
133  ah->ah_turbo = 0;
134  ah->ah_txpower.txp_tpc = 0;
135  ah->ah_imr = 0;
136  ah->ah_atim_window = 0;
137  ah->ah_aifs = AR5K_TUNE_AIFS;
138  ah->ah_cw_min = AR5K_TUNE_CWMIN;
139  ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
140  ah->ah_software_retry = 0;
141  ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;
142 
143  /*
144  * Set the mac version based on the pci id
145  */
146  ah->ah_version = mac_version;
147 
148  /*Fill the ath5k_hw struct with the needed functions*/
150  if (ret)
151  goto err_free;
152 
153  /* Bring device out of sleep and reset it's units */
154  ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, 1);
155  if (ret)
156  goto err_free;
157 
158  /* Get MAC, PHY and RADIO revisions */
159  srev = ath5k_hw_reg_read(ah, AR5K_SREV);
160  ah->ah_mac_srev = srev;
161  ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
162  ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
163  ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID);
164  ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, CHANNEL_5GHZ);
165  ah->ah_phy = AR5K_PHY(0);
166 
167  /* Try to identify radio chip based on it's srev */
168  switch (ah->ah_radio_5ghz_revision & 0xf0) {
169  case AR5K_SREV_RAD_5111:
170  ah->ah_radio = AR5K_RF5111;
171  ah->ah_single_chip = 0;
172  ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
173  CHANNEL_2GHZ);
174  break;
175  case AR5K_SREV_RAD_5112:
176  case AR5K_SREV_RAD_2112:
177  ah->ah_radio = AR5K_RF5112;
178  ah->ah_single_chip = 0;
179  ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
180  CHANNEL_2GHZ);
181  break;
182  case AR5K_SREV_RAD_2413:
183  ah->ah_radio = AR5K_RF2413;
184  ah->ah_single_chip = 1;
185  break;
186  case AR5K_SREV_RAD_5413:
187  ah->ah_radio = AR5K_RF5413;
188  ah->ah_single_chip = 1;
189  break;
190  case AR5K_SREV_RAD_2316:
191  ah->ah_radio = AR5K_RF2316;
192  ah->ah_single_chip = 1;
193  break;
194  case AR5K_SREV_RAD_2317:
195  ah->ah_radio = AR5K_RF2317;
196  ah->ah_single_chip = 1;
197  break;
198  case AR5K_SREV_RAD_5424:
199  if (ah->ah_mac_version == AR5K_SREV_AR2425 ||
200  ah->ah_mac_version == AR5K_SREV_AR2417) {
201  ah->ah_radio = AR5K_RF2425;
202  } else {
203  ah->ah_radio = AR5K_RF5413;
204  }
205  ah->ah_single_chip = 1;
206  break;
207  default:
208  /* Identify radio based on mac/phy srev */
209  if (ah->ah_version == AR5K_AR5210) {
210  ah->ah_radio = AR5K_RF5110;
211  ah->ah_single_chip = 0;
212  } else if (ah->ah_version == AR5K_AR5211) {
213  ah->ah_radio = AR5K_RF5111;
214  ah->ah_single_chip = 0;
215  ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
216  CHANNEL_2GHZ);
217  } else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) ||
218  ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
219  ah->ah_phy_revision == AR5K_SREV_PHY_2425) {
220  ah->ah_radio = AR5K_RF2425;
221  ah->ah_single_chip = 1;
222  ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425;
223  } else if (srev == AR5K_SREV_AR5213A &&
224  ah->ah_phy_revision == AR5K_SREV_PHY_5212B) {
225  ah->ah_radio = AR5K_RF5112;
226  ah->ah_single_chip = 0;
227  ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B;
228  } else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4)) {
229  ah->ah_radio = AR5K_RF2316;
230  ah->ah_single_chip = 1;
231  ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316;
232  } else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) ||
233  ah->ah_phy_revision == AR5K_SREV_PHY_5413) {
234  ah->ah_radio = AR5K_RF5413;
235  ah->ah_single_chip = 1;
236  ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413;
237  } else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) ||
238  ah->ah_phy_revision == AR5K_SREV_PHY_2413) {
239  ah->ah_radio = AR5K_RF2413;
240  ah->ah_single_chip = 1;
241  ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413;
242  } else {
243  DBG("ath5k: Couldn't identify radio revision.\n");
244  ret = -ENOTSUP;
245  goto err_free;
246  }
247  }
248 
249  /* Return on unsuported chips (unsupported eeprom etc) */
250  if ((srev >= AR5K_SREV_AR5416) &&
251  (srev < AR5K_SREV_AR2425)) {
252  DBG("ath5k: Device not yet supported.\n");
253  ret = -ENOTSUP;
254  goto err_free;
255  }
256 
257  /*
258  * Write PCI-E power save settings
259  */
260  if ((ah->ah_version == AR5K_AR5212) &&
262  ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
263  ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
264  /* Shut off RX when elecidle is asserted */
265  ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
266  ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
267  /* TODO: EEPROM work */
268  ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
269  /* Shut off PLL and CLKREQ active in L1 */
270  ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
271  /* Preserce other settings */
272  ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
273  ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
274  ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
275  /* Reset SERDES to load new settings */
277  mdelay(1);
278  }
279 
280  /*
281  * POST
282  */
283  ret = ath5k_hw_post(ah);
284  if (ret)
285  goto err_free;
286 
287  /* Enable pci core retry fix on Hainan (5213A) and later chips */
288  if (srev >= AR5K_SREV_AR5213A)
290 
291  /*
292  * Get card capabilities, calibration values etc
293  * TODO: EEPROM work
294  */
295  ret = ath5k_eeprom_init(ah);
296  if (ret) {
297  DBG("ath5k: unable to init EEPROM\n");
298  goto err_free;
299  }
300 
301  /* Get misc capabilities */
303  if (ret) {
304  DBG("ath5k: unable to get device capabilities: 0x%04x\n",
305  sc->pdev->device);
306  goto err_free;
307  }
308 
309  if (srev >= AR5K_SREV_AR2414) {
310  ah->ah_combined_mic = 1;
313  }
314 
315  /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
316  memset(ah->ah_bssid, 0xff, ETH_ALEN);
317  ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
319 
321 
322  *hw = ah;
323  return 0;
324 err_free:
325  free(ah);
326 err:
327  return ret;
328 }
329 
330 /**
331  * ath5k_hw_detach - Free the ath5k_hw struct
332  *
333  * @ah: The &struct ath5k_hw
334  */
336 {
337  free(ah->ah_rf_banks);
339  free(ah);
340 }
#define AR5K_SREV
Definition: reg.h:957
uint16_t u16
Definition: stdint.h:21
uint32_t c
Definition: md4.c:30
static int ath5k_hw_post(struct ath5k_hw *ah)
ath5k_hw_post - Power On Self Test helper function
Definition: ath5k_attach.c:40
#define AR5K_SREV_RAD_5413
Definition: ath5k.h:318
#define AR5K_SREV_RAD_2112
Definition: ath5k.h:314
int pci_find_capability(struct pci_device *pci, int cap)
Look for a PCI capability.
Definition: pciextra.c:38
#define AR5K_PHY_CHIP_ID
Definition: reg.h:1927
#define AR5K_SREV_PHY_2413
Definition: ath5k.h:329
u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
Definition: ath5k_phy.c:1372
#define AR5K_SREV_REV
Definition: reg.h:958
#define AR5K_PCIE_SERDES
Definition: reg.h:1014
#define AR5K_SREV_AR5414
Definition: ath5k.h:300
#define AR5K_TUNE_ANT_DIVERSITY
Definition: ath5k.h:194
#define AR5K_SREV_PHY_5212B
Definition: ath5k.h:328
#define AR5K_INIT_TX_RETRY
Definition: ath5k.h:228
#define AR5K_PCICFG
Definition: reg.h:880
#define AR5K_REG_MS(_val, _flags)
Definition: ath5k.h:88
#define AR5K_SREV_RAD_5112
Definition: ath5k.h:311
#define AR5K_SREV_AR2417
Definition: ath5k.h:305
#define AR5K_TUNE_CWMIN
Definition: ath5k.h:184
#define AR5K_STA_ID0
Definition: reg.h:1122
void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
ath5k_hw_set_associd - Set BSSID for association
Definition: ath5k_pcu.c:228
Definition: hw.c:16
#define AR5K_SREV_RAD_2413
Definition: ath5k.h:317
#define AR5K_SREV_RAD_5424
Definition: ath5k.h:321
int ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
Definition: ath5k_desc.c:522
ath5k_hw_get_isr - Get interrupt status
Definition: ath5k.h:953
#define ENOTSUP
Operation not supported.
Definition: errno.h:589
#define ENOMEM
Not enough space.
Definition: errno.h:534
#define AR5K_SREV_RAD_2317
Definition: ath5k.h:320
#define AR5K_PCICFG_RETRY_FIX
Definition: reg.h:898
uint16_t device
Device ID.
Definition: pci.h:225
#define AR5K_SREV_RAD_2425
Definition: ath5k.h:322
#define AR5K_PCIE_SERDES_RESET
Definition: reg.h:1015
int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
Definition: ath5k_caps.c:36
int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah)
Definition: ath5k_phy.c:158
#define AR5K_SREV_PHY_2425
Definition: ath5k.h:331
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
#define AR5K_SREV_RAD_5112B
Definition: ath5k.h:313
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:624
#define AR5K_SREV_RAD_2316
Definition: ath5k.h:319
PCI bus.
A PCI device.
Definition: pci.h:206
static void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
Definition: ath5k.h:1222
#define ETH_ALEN
Definition: if_ether.h:8
void ath5k_eeprom_detach(struct ath5k_hw *ah)
int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, int initial)
Definition: ath5k_reset.c:282
int ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version, struct ath5k_hw **hw)
ath5k_hw_attach - Check if hw is supported and init the needed structs
Definition: ath5k_attach.c:112
#define EAGAIN
Resource temporarily unavailable.
Definition: errno.h:318
struct i386_regs regs
Definition: registers.h:15
#define PCI_CAP_ID_EXP
PCI Express.
Definition: pci.h:97
#define AR5K_SREV_AR5213A
Definition: ath5k.h:295
struct pci_device * pdev
Definition: base.h:89
#define AR5K_SREV_AR2425
Definition: ath5k.h:304
#define AR5K_TUNE_AIFS
Definition: ath5k.h:181
#define AR5K_SREV_AR5416
Definition: ath5k.h:302
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:78
#define AR5K_SREV_AR2415
Definition: ath5k.h:301
FILE_LICENCE(MIT)
int ath5k_hw_set_opmode(struct ath5k_hw *ah)
ath5k_hw_set_opmode - Set PCU operating mode
Definition: ath5k_pcu.c:48
#define AR5K_PHY(_n)
Definition: reg.h:1861
#define AR5K_SREV_PHY_5413
Definition: ath5k.h:330
void * iobase
Definition: base.h:90
#define AR5K_SREV_VER
Definition: reg.h:960
#define CHANNEL_5GHZ
Definition: ath5k.h:633
#define AR5K_SREV_RAD_5111
Definition: ath5k.h:308
void ath5k_hw_detach(struct ath5k_hw *ah)
ath5k_hw_detach - Free the ath5k_hw struct
Definition: ath5k_attach.c:335
uint8_t ah
Definition: registers.h:85
static u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
Definition: ath5k.h:1214
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define CHANNEL_B
Definition: ath5k.h:639
#define CHANNEL_2GHZ
Definition: ath5k.h:632
#define AR5K_MISC_MODE
Definition: reg.h:1745
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
int ath5k_eeprom_init(struct ath5k_hw *ah)
uint8_t u8
Definition: stdint.h:19
uint32_t u32
Definition: stdint.h:23
#define AR5K_SREV_AR2414
Definition: ath5k.h:297
#define AR5K_MISC_MODE_COMBINED_MIC
Definition: reg.h:1748
#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags)
Definition: ath5k.h:104
void * memset(void *dest, int character, size_t len) __nonnull