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 FILE_SECBOOT ( FORBIDDEN );
24 
25 /*************************************\
26 * Attach/Detach Functions and helpers *
27 \*************************************/
28 
29 #include <ipxe/pci.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include "ath5k.h"
33 #include "reg.h"
34 #include "base.h"
35 
36 /**
37  * ath5k_hw_post - Power On Self Test helper function
38  *
39  * @ah: The &struct ath5k_hw
40  */
41 static int ath5k_hw_post(struct ath5k_hw *ah)
42 {
43 
44  static const u32 static_pattern[4] = {
45  0x55555555, 0xaaaaaaaa,
46  0x66666666, 0x99999999
47  };
48  static const u16 regs[2] = { AR5K_STA_ID0, AR5K_PHY(8) };
49  int i, c;
50  u16 cur_reg;
51  u32 var_pattern;
52  u32 init_val;
53  u32 cur_val;
54 
55  for (c = 0; c < 2; c++) {
56 
57  cur_reg = regs[c];
58 
59  /* Save previous value */
60  init_val = ath5k_hw_reg_read(ah, cur_reg);
61 
62  for (i = 0; i < 256; i++) {
63  var_pattern = i << 16 | i;
64  ath5k_hw_reg_write(ah, var_pattern, cur_reg);
65  cur_val = ath5k_hw_reg_read(ah, cur_reg);
66 
67  if (cur_val != var_pattern) {
68  DBG("ath5k: POST failed!\n");
69  return -EAGAIN;
70  }
71 
72  /* Found on ndiswrapper dumps */
73  var_pattern = 0x0039080f;
74  ath5k_hw_reg_write(ah, var_pattern, cur_reg);
75  }
76 
77  for (i = 0; i < 4; i++) {
78  var_pattern = static_pattern[i];
79  ath5k_hw_reg_write(ah, var_pattern, cur_reg);
80  cur_val = ath5k_hw_reg_read(ah, cur_reg);
81 
82  if (cur_val != var_pattern) {
83  DBG("ath5k: POST failed!\n");
84  return -EAGAIN;
85  }
86 
87  /* Found on ndiswrapper dumps */
88  var_pattern = 0x003b080f;
89  ath5k_hw_reg_write(ah, var_pattern, cur_reg);
90  }
91 
92  /* Restore previous value */
93  ath5k_hw_reg_write(ah, init_val, cur_reg);
94 
95  }
96 
97  return 0;
98 
99 }
100 
101 /**
102  * ath5k_hw_attach - Check if hw is supported and init the needed structs
103  *
104  * @sc: The &struct ath5k_softc we got from the driver's attach function
105  * @mac_version: The mac version id (check out ath5k.h) based on pci id
106  * @hw: Returned newly allocated hardware structure, on success
107  *
108  * Check if the device is supported, perform a POST and initialize the needed
109  * structs. Returns -ENOMEM if we don't have memory for the needed structs,
110  * -ENODEV if the device is not supported or prints an error msg if something
111  * else went wrong.
112  */
113 int ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version,
114  struct ath5k_hw **hw)
115 {
116  struct ath5k_hw *ah;
117  struct pci_device *pdev = sc->pdev;
118  int ret;
119  u32 srev;
120 
121  ah = zalloc(sizeof(struct ath5k_hw));
122  if (ah == NULL) {
123  ret = -ENOMEM;
124  DBG("ath5k: out of memory\n");
125  goto err;
126  }
127 
128  ah->ah_sc = sc;
129  ah->ah_iobase = sc->iobase;
130 
131  /*
132  * HW information
133  */
134  ah->ah_turbo = 0;
135  ah->ah_txpower.txp_tpc = 0;
136  ah->ah_imr = 0;
137  ah->ah_atim_window = 0;
138  ah->ah_aifs = AR5K_TUNE_AIFS;
139  ah->ah_cw_min = AR5K_TUNE_CWMIN;
140  ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
141  ah->ah_software_retry = 0;
142  ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;
143 
144  /*
145  * Set the mac version based on the pci id
146  */
147  ah->ah_version = mac_version;
148 
149  /*Fill the ath5k_hw struct with the needed functions*/
151  if (ret)
152  goto err_free;
153 
154  /* Bring device out of sleep and reset it's units */
155  ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, 1);
156  if (ret)
157  goto err_free;
158 
159  /* Get MAC, PHY and RADIO revisions */
160  srev = ath5k_hw_reg_read(ah, AR5K_SREV);
161  ah->ah_mac_srev = srev;
162  ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
163  ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
164  ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID);
165  ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, CHANNEL_5GHZ);
166  ah->ah_phy = AR5K_PHY(0);
167 
168  /* Try to identify radio chip based on it's srev */
169  switch (ah->ah_radio_5ghz_revision & 0xf0) {
170  case AR5K_SREV_RAD_5111:
171  ah->ah_radio = AR5K_RF5111;
172  ah->ah_single_chip = 0;
173  ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
174  CHANNEL_2GHZ);
175  break;
176  case AR5K_SREV_RAD_5112:
177  case AR5K_SREV_RAD_2112:
178  ah->ah_radio = AR5K_RF5112;
179  ah->ah_single_chip = 0;
180  ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
181  CHANNEL_2GHZ);
182  break;
183  case AR5K_SREV_RAD_2413:
184  ah->ah_radio = AR5K_RF2413;
185  ah->ah_single_chip = 1;
186  break;
187  case AR5K_SREV_RAD_5413:
188  ah->ah_radio = AR5K_RF5413;
189  ah->ah_single_chip = 1;
190  break;
191  case AR5K_SREV_RAD_2316:
192  ah->ah_radio = AR5K_RF2316;
193  ah->ah_single_chip = 1;
194  break;
195  case AR5K_SREV_RAD_2317:
196  ah->ah_radio = AR5K_RF2317;
197  ah->ah_single_chip = 1;
198  break;
199  case AR5K_SREV_RAD_5424:
200  if (ah->ah_mac_version == AR5K_SREV_AR2425 ||
201  ah->ah_mac_version == AR5K_SREV_AR2417) {
202  ah->ah_radio = AR5K_RF2425;
203  } else {
204  ah->ah_radio = AR5K_RF5413;
205  }
206  ah->ah_single_chip = 1;
207  break;
208  default:
209  /* Identify radio based on mac/phy srev */
210  if (ah->ah_version == AR5K_AR5210) {
211  ah->ah_radio = AR5K_RF5110;
212  ah->ah_single_chip = 0;
213  } else if (ah->ah_version == AR5K_AR5211) {
214  ah->ah_radio = AR5K_RF5111;
215  ah->ah_single_chip = 0;
216  ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
217  CHANNEL_2GHZ);
218  } else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) ||
219  ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
220  ah->ah_phy_revision == AR5K_SREV_PHY_2425) {
221  ah->ah_radio = AR5K_RF2425;
222  ah->ah_single_chip = 1;
223  ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425;
224  } else if (srev == AR5K_SREV_AR5213A &&
225  ah->ah_phy_revision == AR5K_SREV_PHY_5212B) {
226  ah->ah_radio = AR5K_RF5112;
227  ah->ah_single_chip = 0;
228  ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B;
229  } else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4)) {
230  ah->ah_radio = AR5K_RF2316;
231  ah->ah_single_chip = 1;
232  ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316;
233  } else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) ||
234  ah->ah_phy_revision == AR5K_SREV_PHY_5413) {
235  ah->ah_radio = AR5K_RF5413;
236  ah->ah_single_chip = 1;
237  ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413;
238  } else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) ||
239  ah->ah_phy_revision == AR5K_SREV_PHY_2413) {
240  ah->ah_radio = AR5K_RF2413;
241  ah->ah_single_chip = 1;
242  ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413;
243  } else {
244  DBG("ath5k: Couldn't identify radio revision.\n");
245  ret = -ENOTSUP;
246  goto err_free;
247  }
248  }
249 
250  /* Return on unsuported chips (unsupported eeprom etc) */
251  if ((srev >= AR5K_SREV_AR5416) &&
252  (srev < AR5K_SREV_AR2425)) {
253  DBG("ath5k: Device not yet supported.\n");
254  ret = -ENOTSUP;
255  goto err_free;
256  }
257 
258  /*
259  * Write PCI-E power save settings
260  */
261  if ((ah->ah_version == AR5K_AR5212) &&
263  ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
264  ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
265  /* Shut off RX when elecidle is asserted */
266  ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
267  ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
268  /* TODO: EEPROM work */
269  ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
270  /* Shut off PLL and CLKREQ active in L1 */
271  ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
272  /* Preserce other settings */
273  ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
274  ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
275  ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
276  /* Reset SERDES to load new settings */
278  mdelay(1);
279  }
280 
281  /*
282  * POST
283  */
284  ret = ath5k_hw_post(ah);
285  if (ret)
286  goto err_free;
287 
288  /* Enable pci core retry fix on Hainan (5213A) and later chips */
289  if (srev >= AR5K_SREV_AR5213A)
291 
292  /*
293  * Get card capabilities, calibration values etc
294  * TODO: EEPROM work
295  */
296  ret = ath5k_eeprom_init(ah);
297  if (ret) {
298  DBG("ath5k: unable to init EEPROM\n");
299  goto err_free;
300  }
301 
302  /* Get misc capabilities */
304  if (ret) {
305  DBG("ath5k: unable to get device capabilities: 0x%04x\n",
306  sc->pdev->device);
307  goto err_free;
308  }
309 
310  if (srev >= AR5K_SREV_AR2414) {
311  ah->ah_combined_mic = 1;
314  }
315 
316  /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
317  memset(ah->ah_bssid, 0xff, ETH_ALEN);
318  ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
320 
322 
323  *hw = ah;
324  return 0;
325 err_free:
326  free(ah);
327 err:
328  return ret;
329 }
330 
331 /**
332  * ath5k_hw_detach - Free the ath5k_hw struct
333  *
334  * @ah: The &struct ath5k_hw
335  */
337 {
338  free(ah->ah_rf_banks);
340  free(ah);
341 }
#define AR5K_SREV
Definition: reg.h:959
uint16_t u16
Definition: stdint.h:22
static int ath5k_hw_post(struct ath5k_hw *ah)
ath5k_hw_post - Power On Self Test helper function
Definition: ath5k_attach.c:41
#define AR5K_SREV_RAD_5413
Definition: ath5k.h:320
#define AR5K_SREV_RAD_2112
Definition: ath5k.h:316
int pci_find_capability(struct pci_device *pci, int cap)
Look for a PCI capability.
Definition: pciextra.c:39
#define AR5K_PHY_CHIP_ID
Definition: reg.h:1929
#define AR5K_SREV_PHY_2413
Definition: ath5k.h:331
u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
Definition: ath5k_phy.c:1373
#define AR5K_SREV_REV
Definition: reg.h:960
#define AR5K_PCIE_SERDES
Definition: reg.h:1016
#define AR5K_SREV_AR5414
Definition: ath5k.h:302
#define AR5K_TUNE_ANT_DIVERSITY
Definition: ath5k.h:196
#define AR5K_SREV_PHY_5212B
Definition: ath5k.h:330
#define AR5K_INIT_TX_RETRY
Definition: ath5k.h:230
#define AR5K_PCICFG
Definition: reg.h:882
#define AR5K_REG_MS(_val, _flags)
Definition: ath5k.h:90
#define AR5K_SREV_RAD_5112
Definition: ath5k.h:313
#define AR5K_SREV_AR2417
Definition: ath5k.h:307
#define AR5K_TUNE_CWMIN
Definition: ath5k.h:186
#define AR5K_STA_ID0
Definition: reg.h:1124
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:229
Definition: hw.c:16
#define AR5K_SREV_RAD_2413
Definition: ath5k.h:319
#define AR5K_SREV_RAD_5424
Definition: ath5k.h:323
int ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
Definition: ath5k_desc.c:523
ath5k_hw_get_isr - Get interrupt status
Definition: ath5k.h:955
#define ENOTSUP
Operation not supported.
Definition: errno.h:590
#define ENOMEM
Not enough space.
Definition: errno.h:535
#define AR5K_SREV_RAD_2317
Definition: ath5k.h:322
#define AR5K_PCICFG_RETRY_FIX
Definition: reg.h:900
uint16_t device
Device ID.
Definition: pci.h:230
#define AR5K_SREV_RAD_2425
Definition: ath5k.h:324
#define AR5K_PCIE_SERDES_RESET
Definition: reg.h:1017
int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
Definition: ath5k_caps.c:37
int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah)
Definition: ath5k_phy.c:159
#define AR5K_SREV_PHY_2425
Definition: ath5k.h:333
FILE_SECBOOT(FORBIDDEN)
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
#define AR5K_SREV_RAD_5112B
Definition: ath5k.h:315
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:662
#define AR5K_SREV_RAD_2316
Definition: ath5k.h:321
PCI bus.
A PCI device.
Definition: pci.h:211
static void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
Definition: ath5k.h:1224
#define ETH_ALEN
Definition: if_ether.h:9
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:283
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:113
#define EAGAIN
Resource temporarily unavailable.
Definition: errno.h:319
struct i386_regs regs
Definition: registers.h:15
#define PCI_CAP_ID_EXP
PCI Express.
Definition: pci.h:98
#define AR5K_SREV_AR5213A
Definition: ath5k.h:297
struct pci_device * pdev
Definition: base.h:90
#define AR5K_SREV_AR2425
Definition: ath5k.h:306
#define AR5K_TUNE_AIFS
Definition: ath5k.h:183
#define AR5K_SREV_AR5416
Definition: ath5k.h:304
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:79
#define AR5K_SREV_AR2415
Definition: ath5k.h:303
FILE_LICENCE(MIT)
int ath5k_hw_set_opmode(struct ath5k_hw *ah)
ath5k_hw_set_opmode - Set PCU operating mode
Definition: ath5k_pcu.c:49
#define AR5K_PHY(_n)
Definition: reg.h:1863
#define AR5K_SREV_PHY_5413
Definition: ath5k.h:332
void * iobase
Definition: base.h:91
#define AR5K_SREV_VER
Definition: reg.h:962
#define CHANNEL_5GHZ
Definition: ath5k.h:635
#define AR5K_SREV_RAD_5111
Definition: ath5k.h:310
void ath5k_hw_detach(struct ath5k_hw *ah)
ath5k_hw_detach - Free the ath5k_hw struct
Definition: ath5k_attach.c:336
uint8_t ah
Definition: registers.h:85
static u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
Definition: ath5k.h:1216
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define CHANNEL_B
Definition: ath5k.h:641
#define CHANNEL_2GHZ
Definition: ath5k.h:634
#define AR5K_MISC_MODE
Definition: reg.h:1747
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
int ath5k_eeprom_init(struct ath5k_hw *ah)
uint8_t u8
Definition: stdint.h:20
uint32_t u32
Definition: stdint.h:24
#define AR5K_SREV_AR2414
Definition: ath5k.h:299
#define AR5K_MISC_MODE_COMBINED_MIC
Definition: reg.h:1750
#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags)
Definition: ath5k.h:106
void * memset(void *dest, int character, size_t len) __nonnull