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
23FILE_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 */
41static 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 */
113int 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 */
156 if (ret)
157 goto err_free;
158
159 /* Get MAC, PHY and RADIO revisions */
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) {
171 ah->ah_radio = AR5K_RF5111;
172 ah->ah_single_chip = 0;
173 ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
175 break;
178 ah->ah_radio = AR5K_RF5112;
179 ah->ah_single_chip = 0;
180 ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
182 break;
184 ah->ah_radio = AR5K_RF2413;
185 ah->ah_single_chip = 1;
186 break;
188 ah->ah_radio = AR5K_RF5413;
189 ah->ah_single_chip = 1;
190 break;
192 ah->ah_radio = AR5K_RF2316;
193 ah->ah_single_chip = 1;
194 break;
196 ah->ah_radio = AR5K_RF2317;
197 ah->ah_single_chip = 1;
198 break;
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,
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) &&
265 /* Shut off RX when elecidle is asserted */
268 /* TODO: EEPROM work */
270 /* Shut off PLL and CLKREQ active in L1 */
272 /* Preserce other settings */
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;
325err_free:
326 free(ah);
327err:
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 NULL
NULL pointer (VOID *)
Definition Base.h:322
#define AR5K_SREV
Definition reg.h:954
#define AR5K_PHY_CHIP_ID
Definition reg.h:1922
#define AR5K_PCIE_SERDES
Definition reg.h:1009
#define AR5K_SREV_REV
Definition reg.h:955
#define AR5K_MISC_MODE
Definition reg.h:1740
#define AR5K_PCIE_SERDES_RESET
Definition reg.h:1010
#define AR5K_MISC_MODE_COMBINED_MIC
Definition reg.h:1743
#define AR5K_PCICFG
Definition reg.h:877
#define AR5K_PHY(_n)
Definition reg.h:1856
#define AR5K_STA_ID0
Definition reg.h:1117
#define AR5K_SREV_VER
Definition reg.h:957
#define AR5K_PCICFG_RETRY_FIX
Definition reg.h:895
#define AR5K_SREV_RAD_5112B
Definition ath5k.h:315
int ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
Definition ath5k_desc.c:523
#define AR5K_SREV_AR2414
Definition ath5k.h:299
#define CHANNEL_B
Definition ath5k.h:641
#define AR5K_TUNE_ANT_DIVERSITY
Definition ath5k.h:196
#define AR5K_SREV_RAD_5112
Definition ath5k.h:313
#define AR5K_SREV_RAD_2112
Definition ath5k.h:316
#define CHANNEL_5GHZ
Definition ath5k.h:635
void ath5k_eeprom_detach(struct ath5k_hw *ah)
int ath5k_hw_set_opmode(struct ath5k_hw *ah)
ath5k_hw_set_opmode - Set PCU operating mode
Definition ath5k_pcu.c:49
#define AR5K_SREV_RAD_2317
Definition ath5k.h:322
#define AR5K_SREV_AR2415
Definition ath5k.h:303
#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags)
Definition ath5k.h:106
#define AR5K_SREV_RAD_2425
Definition ath5k.h:324
#define AR5K_SREV_AR5213A
Definition ath5k.h:297
#define AR5K_TUNE_AIFS
Definition ath5k.h:183
#define AR5K_REG_MS(_val, _flags)
Definition ath5k.h:90
#define AR5K_SREV_AR2417
Definition ath5k.h:307
#define AR5K_SREV_AR2425
Definition ath5k.h:306
int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
Definition ath5k_caps.c:37
static u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
Definition ath5k.h:1216
#define AR5K_SREV_PHY_2413
Definition ath5k.h:331
#define AR5K_SREV_AR5414
Definition ath5k.h:302
#define AR5K_SREV_RAD_5413
Definition ath5k.h:320
int ath5k_eeprom_init(struct ath5k_hw *ah)
int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah)
Definition ath5k_phy.c:159
@ AR5K_AR5210
Definition ath5k.h:256
@ AR5K_AR5212
Definition ath5k.h:258
@ AR5K_AR5211
Definition ath5k.h:257
#define AR5K_INIT_TX_RETRY
Definition ath5k.h:230
@ AR5K_RF2425
Definition ath5k.h:270
@ AR5K_RF5111
Definition ath5k.h:264
@ AR5K_RF5112
Definition ath5k.h:265
@ AR5K_RF5110
Definition ath5k.h:263
@ AR5K_RF2316
Definition ath5k.h:268
@ AR5K_RF5413
Definition ath5k.h:267
@ AR5K_RF2317
Definition ath5k.h:269
@ AR5K_RF2413
Definition ath5k.h:266
#define AR5K_SREV_AR5416
Definition ath5k.h:304
static void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
Definition ath5k.h:1224
#define AR5K_SREV_PHY_5212B
Definition ath5k.h:330
#define AR5K_SREV_RAD_2413
Definition ath5k.h:319
u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
Definition ath5k_phy.c:1373
#define AR5K_SREV_RAD_5424
Definition ath5k.h:323
#define AR5K_SREV_PHY_5413
Definition ath5k.h:332
#define AR5K_SREV_RAD_5111
Definition ath5k.h:310
#define AR5K_SREV_RAD_2316
Definition ath5k.h:321
#define AR5K_TUNE_CWMIN
Definition ath5k.h:186
int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, int initial)
#define CHANNEL_2GHZ
Definition ath5k.h:634
#define AR5K_SREV_PHY_2425
Definition ath5k.h:333
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
void ath5k_hw_detach(struct ath5k_hw *ah)
ath5k_hw_detach - Free the ath5k_hw struct
static int ath5k_hw_post(struct ath5k_hw *ah)
ath5k_hw_post - Power On Self Test helper function
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
#define DBG(...)
Print a debugging message.
Definition compiler.h:498
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define EAGAIN
Resource temporarily unavailable.
Definition errno.h:319
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
#define ETH_ALEN
Definition if_ether.h:9
#define u8
Definition igbvf_osdep.h:40
void * memset(void *dest, int character, size_t len) __nonnull
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
PCI bus.
#define PCI_CAP_ID_EXP
PCI Express.
Definition pci.h:98
int pci_find_capability(struct pci_device *pci, int cap)
Look for a PCI capability.
Definition pciextra.c:39
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
uint8_t ah
Definition registers.h:1
struct i386_regs regs
Definition registers.h:1
ath5k_hw_get_isr - Get interrupt status
Definition ath5k.h:955
struct pci_device * pdev
Definition base.h:90
void * iobase
Definition base.h:91
Definition hw.c:16
A PCI device.
Definition pci.h:211
uint16_t device
Device ID.
Definition pci.h:230
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition timer.c:79
#define u16
Definition vga.h:20
#define u32
Definition vga.h:21