1 | /* |
2 | * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting |
3 | * Copyright (c) 2002-2008 Atheros Communications, Inc. |
4 | * |
5 | * Permission to use, copy, modify, and/or 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 | * $Id: ar5212_misc.c,v 1.3 2012/02/12 13:48:45 wiz Exp $ |
18 | */ |
19 | #include "opt_ah.h" |
20 | |
21 | #include "ah.h" |
22 | #include "ah_internal.h" |
23 | #include "ah_devid.h" |
24 | #ifdef AH_DEBUG |
25 | #include "ah_desc.h" /* NB: for HAL_PHYERR* */ |
26 | #endif |
27 | |
28 | #include "ar5212/ar5212.h" |
29 | #include "ar5212/ar5212reg.h" |
30 | #include "ar5212/ar5212phy.h" |
31 | |
32 | #include "ah_eeprom_v3.h" |
33 | |
34 | #define AR_NUM_GPIO 6 /* 6 GPIO pins */ |
35 | #define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */ |
36 | |
37 | extern void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *); |
38 | |
39 | void |
40 | ar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac) |
41 | { |
42 | struct ath_hal_5212 *ahp = AH5212(ah); |
43 | |
44 | OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); |
45 | } |
46 | |
47 | HAL_BOOL |
48 | ar5212SetMacAddress(struct ath_hal *ah, const uint8_t *mac) |
49 | { |
50 | struct ath_hal_5212 *ahp = AH5212(ah); |
51 | |
52 | OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); |
53 | return AH_TRUE; |
54 | } |
55 | |
56 | void |
57 | ar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mask) |
58 | { |
59 | struct ath_hal_5212 *ahp = AH5212(ah); |
60 | |
61 | OS_MEMCPY(mask, ahp->ah_bssidmask, IEEE80211_ADDR_LEN); |
62 | } |
63 | |
64 | HAL_BOOL |
65 | ar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) |
66 | { |
67 | struct ath_hal_5212 *ahp = AH5212(ah); |
68 | |
69 | /* save it since it must be rewritten on reset */ |
70 | OS_MEMCPY(ahp->ah_bssidmask, mask, IEEE80211_ADDR_LEN); |
71 | |
72 | OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); |
73 | OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); |
74 | return AH_TRUE; |
75 | } |
76 | |
77 | /* |
78 | * Attempt to change the cards operating regulatory domain to the given value |
79 | */ |
80 | HAL_BOOL |
81 | ar5212SetRegulatoryDomain(struct ath_hal *ah, |
82 | uint16_t regDomain, HAL_STATUS *status) |
83 | { |
84 | HAL_STATUS ecode; |
85 | |
86 | if (AH_PRIVATE(ah)->ah_currentRD == regDomain) { |
87 | ecode = HAL_EINVAL; |
88 | goto bad; |
89 | } |
90 | if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) { |
91 | ecode = HAL_EEWRITE; |
92 | goto bad; |
93 | } |
94 | #ifdef AH_SUPPORT_WRITE_REGDOMAIN |
95 | if (ath_hal_eepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) { |
96 | HALDEBUG(ah, HAL_DEBUG_ANY, |
97 | "%s: set regulatory domain to %u (0x%x)\n" , |
98 | __func__, regDomain, regDomain); |
99 | AH_PRIVATE(ah)->ah_currentRD = regDomain; |
100 | return AH_TRUE; |
101 | } |
102 | #endif |
103 | ecode = HAL_EIO; |
104 | bad: |
105 | if (status) |
106 | *status = ecode; |
107 | return AH_FALSE; |
108 | } |
109 | |
110 | /* |
111 | * Return the wireless modes (a,b,g,t) supported by hardware. |
112 | * |
113 | * This value is what is actually supported by the hardware |
114 | * and is unaffected by regulatory/country code settings. |
115 | */ |
116 | u_int |
117 | ar5212GetWirelessModes(struct ath_hal *ah) |
118 | { |
119 | u_int mode = 0; |
120 | |
121 | if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { |
122 | mode = HAL_MODE_11A; |
123 | if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) |
124 | mode |= HAL_MODE_TURBO | HAL_MODE_108A; |
125 | if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) |
126 | mode |= HAL_MODE_11A_HALF_RATE; |
127 | if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) |
128 | mode |= HAL_MODE_11A_QUARTER_RATE; |
129 | } |
130 | if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) |
131 | mode |= HAL_MODE_11B; |
132 | if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) && |
133 | AH_PRIVATE(ah)->ah_subvendorid != AR_SUBVENDOR_ID_NOG) { |
134 | mode |= HAL_MODE_11G; |
135 | if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE)) |
136 | mode |= HAL_MODE_108G; |
137 | if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) |
138 | mode |= HAL_MODE_11G_HALF_RATE; |
139 | if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) |
140 | mode |= HAL_MODE_11G_QUARTER_RATE; |
141 | } |
142 | return mode; |
143 | } |
144 | |
145 | /* |
146 | * Set the interrupt and GPIO values so the ISR can disable RF |
147 | * on a switch signal. Assumes GPIO port and interrupt polarity |
148 | * are set prior to call. |
149 | */ |
150 | void |
151 | ar5212EnableRfKill(struct ath_hal *ah) |
152 | { |
153 | uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; |
154 | int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); |
155 | int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); |
156 | |
157 | /* |
158 | * Configure the desired GPIO port for input |
159 | * and enable baseband rf silence. |
160 | */ |
161 | ath_hal_gpioCfgInput(ah, select); |
162 | OS_REG_SET_BIT(ah, AR_PHY(0), 0x00002000); |
163 | /* |
164 | * If radio disable switch connection to GPIO bit x is enabled |
165 | * program GPIO interrupt. |
166 | * If rfkill bit on eeprom is 1, setupeeprommap routine has already |
167 | * verified that it is a later version of eeprom, it has a place for |
168 | * rfkill bit and it is set to 1, indicating that GPIO bit x hardware |
169 | * connection is present. |
170 | */ |
171 | ath_hal_gpioSetIntr(ah, select, |
172 | (ath_hal_gpioGet(ah, select) == polarity ? !polarity : polarity)); |
173 | } |
174 | |
175 | /* |
176 | * Change the LED blinking pattern to correspond to the connectivity |
177 | */ |
178 | void |
179 | ar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state) |
180 | { |
181 | static const uint32_t ledbits[8] = { |
182 | AR_PCICFG_LEDCTL_NONE, /* HAL_LED_INIT */ |
183 | AR_PCICFG_LEDCTL_PEND, /* HAL_LED_SCAN */ |
184 | AR_PCICFG_LEDCTL_PEND, /* HAL_LED_AUTH */ |
185 | AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_ASSOC*/ |
186 | AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_RUN */ |
187 | AR_PCICFG_LEDCTL_NONE, |
188 | AR_PCICFG_LEDCTL_NONE, |
189 | AR_PCICFG_LEDCTL_NONE, |
190 | }; |
191 | uint32_t bits; |
192 | |
193 | bits = OS_REG_READ(ah, AR_PCICFG); |
194 | if (IS_2417(ah)) { |
195 | /* |
196 | * Enable LED for Nala. There is a bit marked reserved |
197 | * that must be set and we also turn on the power led. |
198 | * Because we mark s/w LED control setting the control |
199 | * status bits below is meangless (the driver must flash |
200 | * the LED(s) using the GPIO lines). |
201 | */ |
202 | bits = (bits &~ AR_PCICFG_LEDMODE) |
203 | | SM(AR_PCICFG_LEDMODE_POWON, AR_PCICFG_LEDMODE) |
204 | #if 0 |
205 | | SM(AR_PCICFG_LEDMODE_NETON, AR_PCICFG_LEDMODE) |
206 | #endif |
207 | | 0x08000000; |
208 | } |
209 | bits = (bits &~ AR_PCICFG_LEDCTL) |
210 | | SM(ledbits[state & 0x7], AR_PCICFG_LEDCTL); |
211 | OS_REG_WRITE(ah, AR_PCICFG, bits); |
212 | } |
213 | |
214 | /* |
215 | * Change association related fields programmed into the hardware. |
216 | * Writing a valid BSSID to the hardware effectively enables the hardware |
217 | * to synchronize its TSF to the correct beacons and receive frames coming |
218 | * from that BSSID. It is called by the SME JOIN operation. |
219 | */ |
220 | void |
221 | ar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) |
222 | { |
223 | struct ath_hal_5212 *ahp = AH5212(ah); |
224 | |
225 | /* XXX save bssid for possible re-use on reset */ |
226 | OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); |
227 | OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); |
228 | OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | |
229 | ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S)); |
230 | } |
231 | |
232 | /* |
233 | * Get the current hardware tsf for stamlme |
234 | */ |
235 | uint64_t |
236 | ar5212GetTsf64(struct ath_hal *ah) |
237 | { |
238 | uint32_t low1, low2, u32; |
239 | |
240 | /* sync multi-word read */ |
241 | low1 = OS_REG_READ(ah, AR_TSF_L32); |
242 | u32 = OS_REG_READ(ah, AR_TSF_U32); |
243 | low2 = OS_REG_READ(ah, AR_TSF_L32); |
244 | if (low2 < low1) { /* roll over */ |
245 | /* |
246 | * If we are not preempted this will work. If we are |
247 | * then we re-reading AR_TSF_U32 does no good as the |
248 | * low bits will be meaningless. Likewise reading |
249 | * L32, U32, U32, then comparing the last two reads |
250 | * to check for rollover doesn't help if preempted--so |
251 | * we take this approach as it costs one less PCI read |
252 | * which can be noticeable when doing things like |
253 | * timestamping packets in monitor mode. |
254 | */ |
255 | u32++; |
256 | } |
257 | return (((uint64_t) u32) << 32) | ((uint64_t) low2); |
258 | } |
259 | |
260 | /* |
261 | * Get the current hardware tsf for stamlme |
262 | */ |
263 | uint32_t |
264 | ar5212GetTsf32(struct ath_hal *ah) |
265 | { |
266 | return OS_REG_READ(ah, AR_TSF_L32); |
267 | } |
268 | |
269 | /* |
270 | * Reset the current hardware tsf for stamlme. |
271 | */ |
272 | void |
273 | ar5212ResetTsf(struct ath_hal *ah) |
274 | { |
275 | |
276 | uint32_t val = OS_REG_READ(ah, AR_BEACON); |
277 | |
278 | OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); |
279 | /* |
280 | * When resetting the TSF, write twice to the |
281 | * corresponding register; each write to the RESET_TSF bit toggles |
282 | * the internal signal to cause a reset of the TSF - but if the signal |
283 | * is left high, it will reset the TSF on the next chip reset also! |
284 | * writing the bit an even number of times fixes this issue |
285 | */ |
286 | OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); |
287 | } |
288 | |
289 | /* |
290 | * Set or clear hardware basic rate bit |
291 | * Set hardware basic rate set if basic rate is found |
292 | * and basic rate is equal or less than 2Mbps |
293 | */ |
294 | void |
295 | ar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *rs) |
296 | { |
297 | HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; |
298 | uint32_t reg; |
299 | uint8_t xset; |
300 | int i; |
301 | |
302 | if (chan == AH_NULL || !IS_CHAN_CCK(chan)) |
303 | return; |
304 | xset = 0; |
305 | for (i = 0; i < rs->rs_count; i++) { |
306 | uint8_t rset = rs->rs_rates[i]; |
307 | /* Basic rate defined? */ |
308 | if ((rset & 0x80) && (rset &= 0x7f) >= xset) |
309 | xset = rset; |
310 | } |
311 | /* |
312 | * Set the h/w bit to reflect whether or not the basic |
313 | * rate is found to be equal or less than 2Mbps. |
314 | */ |
315 | reg = OS_REG_READ(ah, AR_STA_ID1); |
316 | if (xset && xset/2 <= 2) |
317 | OS_REG_WRITE(ah, AR_STA_ID1, reg | AR_STA_ID1_BASE_RATE_11B); |
318 | else |
319 | OS_REG_WRITE(ah, AR_STA_ID1, reg &~ AR_STA_ID1_BASE_RATE_11B); |
320 | } |
321 | |
322 | /* |
323 | * Grab a semi-random value from hardware registers - may not |
324 | * change often |
325 | */ |
326 | uint32_t |
327 | ar5212GetRandomSeed(struct ath_hal *ah) |
328 | { |
329 | uint32_t nf; |
330 | |
331 | nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; |
332 | if (nf & 0x100) |
333 | nf = 0 - ((nf ^ 0x1ff) + 1); |
334 | return (OS_REG_READ(ah, AR_TSF_U32) ^ |
335 | OS_REG_READ(ah, AR_TSF_L32) ^ nf); |
336 | } |
337 | |
338 | /* |
339 | * Detect if our card is present |
340 | */ |
341 | HAL_BOOL |
342 | ar5212DetectCardPresent(struct ath_hal *ah) |
343 | { |
344 | uint16_t macVersion, macRev; |
345 | uint32_t v; |
346 | |
347 | /* |
348 | * Read the Silicon Revision register and compare that |
349 | * to what we read at attach time. If the same, we say |
350 | * a card/device is present. |
351 | */ |
352 | v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID; |
353 | macVersion = v >> AR_SREV_ID_S; |
354 | macRev = v & AR_SREV_REVISION; |
355 | return (AH_PRIVATE(ah)->ah_macVersion == macVersion && |
356 | AH_PRIVATE(ah)->ah_macRev == macRev); |
357 | } |
358 | |
359 | void |
360 | ar5212EnableMibCounters(struct ath_hal *ah) |
361 | { |
362 | /* NB: this just resets the mib counter machinery */ |
363 | OS_REG_WRITE(ah, AR_MIBC, |
364 | ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); |
365 | } |
366 | |
367 | void |
368 | ar5212DisableMibCounters(struct ath_hal *ah) |
369 | { |
370 | OS_REG_WRITE(ah, AR_MIBC, AR_MIBC | AR_MIBC_CMC); |
371 | } |
372 | |
373 | /* |
374 | * Update MIB Counters |
375 | */ |
376 | void |
377 | ar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats) |
378 | { |
379 | stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); |
380 | stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); |
381 | stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); |
382 | stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); |
383 | stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); |
384 | } |
385 | |
386 | /* |
387 | * Detect if the HW supports spreading a CCK signal on channel 14 |
388 | */ |
389 | HAL_BOOL |
390 | ar5212IsJapanChannelSpreadSupported(struct ath_hal *ah) |
391 | { |
392 | return AH_TRUE; |
393 | } |
394 | |
395 | /* |
396 | * Get the rssi of frame curently being received. |
397 | */ |
398 | uint32_t |
399 | (struct ath_hal *ah) |
400 | { |
401 | return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff); |
402 | } |
403 | |
404 | u_int |
405 | ar5212GetDefAntenna(struct ath_hal *ah) |
406 | { |
407 | return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7); |
408 | } |
409 | |
410 | void |
411 | ar5212SetDefAntenna(struct ath_hal *ah, u_int antenna) |
412 | { |
413 | OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); |
414 | } |
415 | |
416 | HAL_ANT_SETTING |
417 | ar5212GetAntennaSwitch(struct ath_hal *ah) |
418 | { |
419 | return AH5212(ah)->ah_antControl; |
420 | } |
421 | |
422 | HAL_BOOL |
423 | ar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING setting) |
424 | { |
425 | struct ath_hal_5212 *ahp = AH5212(ah); |
426 | const HAL_CHANNEL_INTERNAL *ichan = AH_PRIVATE(ah)->ah_curchan; |
427 | |
428 | if (!ahp->ah_phyPowerOn || ichan == AH_NULL) { |
429 | /* PHY powered off, just stash settings */ |
430 | ahp->ah_antControl = setting; |
431 | ahp->ah_diversity = (setting == HAL_ANT_VARIABLE); |
432 | return AH_TRUE; |
433 | } |
434 | return ar5212SetAntennaSwitchInternal(ah, setting, ichan); |
435 | } |
436 | |
437 | HAL_BOOL |
438 | ar5212IsSleepAfterBeaconBroken(struct ath_hal *ah) |
439 | { |
440 | return AH_TRUE; |
441 | } |
442 | |
443 | HAL_BOOL |
444 | ar5212SetSifsTime(struct ath_hal *ah, u_int us) |
445 | { |
446 | struct ath_hal_5212 *ahp = AH5212(ah); |
447 | |
448 | if (us > ath_hal_mac_usec(ah, 0xffff)) { |
449 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n" , |
450 | __func__, us); |
451 | ahp->ah_sifstime = (u_int) -1; /* restore default handling */ |
452 | return AH_FALSE; |
453 | } else { |
454 | /* convert to system clocks */ |
455 | OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us-2)); |
456 | ahp->ah_slottime = us; |
457 | return AH_TRUE; |
458 | } |
459 | } |
460 | |
461 | u_int |
462 | ar5212GetSifsTime(struct ath_hal *ah) |
463 | { |
464 | u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff; |
465 | return ath_hal_mac_usec(ah, clks)+2; /* convert from system clocks */ |
466 | } |
467 | |
468 | HAL_BOOL |
469 | ar5212SetSlotTime(struct ath_hal *ah, u_int us) |
470 | { |
471 | struct ath_hal_5212 *ahp = AH5212(ah); |
472 | |
473 | if (us < HAL_SLOT_TIME_6 || us > ath_hal_mac_usec(ah, 0xffff)) { |
474 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n" , |
475 | __func__, us); |
476 | ahp->ah_slottime = (u_int) -1; /* restore default handling */ |
477 | return AH_FALSE; |
478 | } else { |
479 | /* convert to system clocks */ |
480 | OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us)); |
481 | ahp->ah_slottime = us; |
482 | return AH_TRUE; |
483 | } |
484 | } |
485 | |
486 | u_int |
487 | ar5212GetSlotTime(struct ath_hal *ah) |
488 | { |
489 | u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff; |
490 | return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ |
491 | } |
492 | |
493 | HAL_BOOL |
494 | ar5212SetAckTimeout(struct ath_hal *ah, u_int us) |
495 | { |
496 | struct ath_hal_5212 *ahp = AH5212(ah); |
497 | |
498 | if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { |
499 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n" , |
500 | __func__, us); |
501 | ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ |
502 | return AH_FALSE; |
503 | } else { |
504 | /* convert to system clocks */ |
505 | OS_REG_RMW_FIELD(ah, AR_TIME_OUT, |
506 | AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); |
507 | ahp->ah_acktimeout = us; |
508 | return AH_TRUE; |
509 | } |
510 | } |
511 | |
512 | u_int |
513 | ar5212GetAckTimeout(struct ath_hal *ah) |
514 | { |
515 | u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); |
516 | return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ |
517 | } |
518 | |
519 | u_int |
520 | ar5212GetAckCTSRate(struct ath_hal *ah) |
521 | { |
522 | return ((AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); |
523 | } |
524 | |
525 | HAL_BOOL |
526 | ar5212SetAckCTSRate(struct ath_hal *ah, u_int high) |
527 | { |
528 | struct ath_hal_5212 *ahp = AH5212(ah); |
529 | |
530 | if (high) { |
531 | OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); |
532 | ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; |
533 | } else { |
534 | OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); |
535 | ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; |
536 | } |
537 | return AH_TRUE; |
538 | } |
539 | |
540 | HAL_BOOL |
541 | ar5212SetCTSTimeout(struct ath_hal *ah, u_int us) |
542 | { |
543 | struct ath_hal_5212 *ahp = AH5212(ah); |
544 | |
545 | if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { |
546 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n" , |
547 | __func__, us); |
548 | ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ |
549 | return AH_FALSE; |
550 | } else { |
551 | /* convert to system clocks */ |
552 | OS_REG_RMW_FIELD(ah, AR_TIME_OUT, |
553 | AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); |
554 | ahp->ah_ctstimeout = us; |
555 | return AH_TRUE; |
556 | } |
557 | } |
558 | |
559 | u_int |
560 | ar5212GetCTSTimeout(struct ath_hal *ah) |
561 | { |
562 | u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); |
563 | return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ |
564 | } |
565 | |
566 | /* Setup decompression for given key index */ |
567 | HAL_BOOL |
568 | ar5212SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) |
569 | { |
570 | struct ath_hal_5212 *ahp = AH5212(ah); |
571 | |
572 | if (keyidx >= HAL_DECOMP_MASK_SIZE) |
573 | return AH_FALSE; |
574 | OS_REG_WRITE(ah, AR_DCM_A, keyidx); |
575 | OS_REG_WRITE(ah, AR_DCM_D, en ? AR_DCM_D_EN : 0); |
576 | ahp->ah_decompMask[keyidx] = en; |
577 | |
578 | return AH_TRUE; |
579 | } |
580 | |
581 | /* Setup coverage class */ |
582 | void |
583 | ar5212SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) |
584 | { |
585 | uint32_t slot, timeout, eifs; |
586 | u_int clkRate; |
587 | |
588 | AH_PRIVATE(ah)->ah_coverageClass = coverageclass; |
589 | |
590 | if (now) { |
591 | if (AH_PRIVATE(ah)->ah_coverageClass == 0) |
592 | return; |
593 | |
594 | /* Don't apply coverage class to non A channels */ |
595 | if (!IS_CHAN_A(AH_PRIVATE(ah)->ah_curchan)) |
596 | return; |
597 | |
598 | /* Get core clock rate */ |
599 | clkRate = ath_hal_mac_clks(ah, 1); |
600 | |
601 | /* Compute EIFS */ |
602 | slot = coverageclass * 3 * clkRate; |
603 | eifs = coverageclass * 6 * clkRate; |
604 | if (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) { |
605 | slot += IFS_SLOT_HALF_RATE; |
606 | eifs += IFS_EIFS_HALF_RATE; |
607 | } else if (IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan)) { |
608 | slot += IFS_SLOT_QUARTER_RATE; |
609 | eifs += IFS_EIFS_QUARTER_RATE; |
610 | } else { /* full rate */ |
611 | slot += IFS_SLOT_FULL_RATE; |
612 | eifs += IFS_EIFS_FULL_RATE; |
613 | } |
614 | |
615 | /* |
616 | * Add additional time for air propagation for ACK and CTS |
617 | * timeouts. This value is in core clocks. |
618 | */ |
619 | timeout = ACK_CTS_TIMEOUT_11A + (coverageclass * 3 * clkRate); |
620 | |
621 | /* |
622 | * Write the values: slot, eifs, ack/cts timeouts. |
623 | */ |
624 | OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot); |
625 | OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs); |
626 | OS_REG_WRITE(ah, AR_TIME_OUT, |
627 | SM(timeout, AR_TIME_OUT_CTS) |
628 | | SM(timeout, AR_TIME_OUT_ACK)); |
629 | } |
630 | } |
631 | |
632 | void |
633 | ar5212SetPCUConfig(struct ath_hal *ah) |
634 | { |
635 | ar5212SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); |
636 | } |
637 | |
638 | /* |
639 | * Return whether an external 32KHz crystal should be used |
640 | * to reduce power consumption when sleeping. We do so if |
641 | * the crystal is present (obtained from EEPROM) and if we |
642 | * are not running as an AP and are configured to use it. |
643 | */ |
644 | HAL_BOOL |
645 | ar5212Use32KHzclock(struct ath_hal *ah, HAL_OPMODE opmode) |
646 | { |
647 | if (opmode != HAL_M_HOSTAP) { |
648 | struct ath_hal_5212 *ahp = AH5212(ah); |
649 | return ath_hal_eepromGetFlag(ah, AR_EEP_32KHZCRYSTAL) && |
650 | (ahp->ah_enable32kHzClock == USE_32KHZ || |
651 | ahp->ah_enable32kHzClock == AUTO_32KHZ); |
652 | } else |
653 | return AH_FALSE; |
654 | } |
655 | |
656 | /* |
657 | * If 32KHz clock exists, use it to lower power consumption during sleep |
658 | * |
659 | * Note: If clock is set to 32 KHz, delays on accessing certain |
660 | * baseband registers (27-31, 124-127) are required. |
661 | */ |
662 | void |
663 | ar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode) |
664 | { |
665 | if (ar5212Use32KHzclock(ah, opmode)) { |
666 | /* |
667 | * Enable clocks to be turned OFF in BB during sleep |
668 | * and also enable turning OFF 32MHz/40MHz Refclk |
669 | * from A2. |
670 | */ |
671 | OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); |
672 | OS_REG_WRITE(ah, AR_PHY_REFCLKPD, |
673 | IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); |
674 | OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1); |
675 | OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */ |
676 | OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 1); |
677 | |
678 | if (IS_2413(ah) || IS_5413(ah) || IS_2417(ah)) { |
679 | OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x26); |
680 | OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0d); |
681 | OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x07); |
682 | OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x3f); |
683 | /* # Set sleep clock rate to 32 KHz. */ |
684 | OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x2); |
685 | } else { |
686 | OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x0a); |
687 | OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c); |
688 | OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03); |
689 | OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x20); |
690 | OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x3); |
691 | } |
692 | } else { |
693 | OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x0); |
694 | OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); |
695 | |
696 | OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32MHz TSF inc */ |
697 | |
698 | OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); |
699 | OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); |
700 | |
701 | if (IS_2417(ah)) |
702 | OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0a); |
703 | else if (IS_HB63(ah)) |
704 | OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x32); |
705 | else |
706 | OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); |
707 | OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); |
708 | OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); |
709 | OS_REG_WRITE(ah, AR_PHY_REFCLKPD, |
710 | IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2417(ah) ? 0x14 : 0x18); |
711 | OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, |
712 | IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); |
713 | } |
714 | } |
715 | |
716 | /* |
717 | * If 32KHz clock exists, turn it off and turn back on the 32Mhz |
718 | */ |
719 | void |
720 | ar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode) |
721 | { |
722 | if (ar5212Use32KHzclock(ah, opmode)) { |
723 | /* # Set sleep clock rate back to 32 MHz. */ |
724 | OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0); |
725 | OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); |
726 | |
727 | OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */ |
728 | OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, |
729 | IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); |
730 | |
731 | /* |
732 | * Restore BB registers to power-on defaults |
733 | */ |
734 | OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); |
735 | OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); |
736 | OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); |
737 | OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); |
738 | OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); |
739 | OS_REG_WRITE(ah, AR_PHY_REFCLKPD, |
740 | IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); |
741 | } |
742 | } |
743 | |
744 | /* |
745 | * Adjust NF based on statistical values for 5GHz frequencies. |
746 | * Default method: this may be overridden by the rf backend. |
747 | */ |
748 | int16_t |
749 | ar5212GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) |
750 | { |
751 | static const struct { |
752 | uint16_t freqLow; |
753 | int16_t adjust; |
754 | } adjustDef[] = { |
755 | { 5790, 11 }, /* NB: ordered high -> low */ |
756 | { 5730, 10 }, |
757 | { 5690, 9 }, |
758 | { 5660, 8 }, |
759 | { 5610, 7 }, |
760 | { 5530, 5 }, |
761 | { 5450, 4 }, |
762 | { 5379, 2 }, |
763 | { 5209, 0 }, |
764 | { 3000, 1 }, |
765 | { 0, 0 }, |
766 | }; |
767 | int i; |
768 | |
769 | for (i = 0; c->channel <= adjustDef[i].freqLow; i++) |
770 | ; |
771 | return adjustDef[i].adjust; |
772 | } |
773 | |
774 | HAL_STATUS |
775 | ar5212GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, |
776 | uint32_t capability, uint32_t *result) |
777 | { |
778 | #define MACVERSION(ah) AH_PRIVATE(ah)->ah_macVersion |
779 | struct ath_hal_5212 *ahp = AH5212(ah); |
780 | const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; |
781 | const struct ar5212AniState *ani; |
782 | |
783 | switch (type) { |
784 | case HAL_CAP_CIPHER: /* cipher handled in hardware */ |
785 | switch (capability) { |
786 | case HAL_CIPHER_AES_CCM: |
787 | return pCap->halCipherAesCcmSupport ? |
788 | HAL_OK : HAL_ENOTSUPP; |
789 | case HAL_CIPHER_AES_OCB: |
790 | case HAL_CIPHER_TKIP: |
791 | case HAL_CIPHER_WEP: |
792 | case HAL_CIPHER_MIC: |
793 | case HAL_CIPHER_CLR: |
794 | return HAL_OK; |
795 | default: |
796 | return HAL_ENOTSUPP; |
797 | } |
798 | case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ |
799 | switch (capability) { |
800 | case 0: /* hardware capability */ |
801 | return HAL_OK; |
802 | case 1: |
803 | return (ahp->ah_staId1Defaults & |
804 | AR_STA_ID1_CRPT_MIC_ENABLE) ? HAL_OK : HAL_ENXIO; |
805 | } |
806 | return HAL_EINVAL; |
807 | case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ |
808 | switch (capability) { |
809 | case 0: /* hardware capability */ |
810 | return pCap->halTkipMicTxRxKeySupport ? |
811 | HAL_ENXIO : HAL_OK; |
812 | case 1: /* current setting */ |
813 | return (ahp->ah_miscMode & |
814 | AR_MISC_MODE_MIC_NEW_LOC_ENABLE) ? HAL_ENXIO : HAL_OK; |
815 | } |
816 | return HAL_EINVAL; |
817 | case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC w/ WMM */ |
818 | /* XXX move to capability bit */ |
819 | return MACVERSION(ah) > AR_SREV_VERSION_VENICE || |
820 | (MACVERSION(ah) == AR_SREV_VERSION_VENICE && |
821 | AH_PRIVATE(ah)->ah_macRev >= 8) ? HAL_OK : HAL_ENOTSUPP; |
822 | case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ |
823 | switch (capability) { |
824 | case 0: /* hardware capability */ |
825 | return HAL_OK; |
826 | case 1: /* current setting */ |
827 | return ahp->ah_diversity ? HAL_OK : HAL_ENXIO; |
828 | } |
829 | return HAL_EINVAL; |
830 | case HAL_CAP_DIAG: |
831 | *result = AH_PRIVATE(ah)->ah_diagreg; |
832 | return HAL_OK; |
833 | case HAL_CAP_TPC: |
834 | switch (capability) { |
835 | case 0: /* hardware capability */ |
836 | return HAL_OK; |
837 | case 1: |
838 | return ahp->ah_tpcEnabled ? HAL_OK : HAL_ENXIO; |
839 | } |
840 | return HAL_OK; |
841 | case HAL_CAP_PHYDIAG: /* radar pulse detection capability */ |
842 | switch (capability) { |
843 | case HAL_CAP_RADAR: |
844 | return ath_hal_eepromGetFlag(ah, AR_EEP_AMODE) ? |
845 | HAL_OK: HAL_ENXIO; |
846 | case HAL_CAP_AR: |
847 | return (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) || |
848 | ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) ? |
849 | HAL_OK: HAL_ENXIO; |
850 | } |
851 | return HAL_ENXIO; |
852 | case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ |
853 | switch (capability) { |
854 | case 0: /* hardware capability */ |
855 | return HAL_OK; |
856 | case 1: |
857 | return (ahp->ah_staId1Defaults & |
858 | AR_STA_ID1_MCAST_KSRCH) ? HAL_OK : HAL_ENXIO; |
859 | } |
860 | return HAL_EINVAL; |
861 | case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ |
862 | switch (capability) { |
863 | case 0: /* hardware capability */ |
864 | return pCap->halTsfAddSupport ? HAL_OK : HAL_ENOTSUPP; |
865 | case 1: |
866 | return (ahp->ah_miscMode & AR_MISC_MODE_TX_ADD_TSF) ? |
867 | HAL_OK : HAL_ENXIO; |
868 | } |
869 | return HAL_EINVAL; |
870 | case HAL_CAP_TPC_ACK: |
871 | *result = MS(ahp->ah_macTPC, AR_TPC_ACK); |
872 | return HAL_OK; |
873 | case HAL_CAP_TPC_CTS: |
874 | *result = MS(ahp->ah_macTPC, AR_TPC_CTS); |
875 | return HAL_OK; |
876 | case HAL_CAP_INTMIT: /* interference mitigation */ |
877 | switch (capability) { |
878 | case 0: /* hardware capability */ |
879 | return HAL_OK; |
880 | case 1: |
881 | return (ahp->ah_procPhyErr & HAL_ANI_ENA) ? |
882 | HAL_OK : HAL_ENXIO; |
883 | case 2: /* HAL_ANI_NOISE_IMMUNITY_LEVEL */ |
884 | case 3: /* HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION */ |
885 | case 4: /* HAL_ANI_CCK_WEAK_SIGNAL_THR */ |
886 | case 5: /* HAL_ANI_FIRSTEP_LEVEL */ |
887 | case 6: /* HAL_ANI_SPUR_IMMUNITY_LEVEL */ |
888 | ani = ar5212AniGetCurrentState(ah); |
889 | if (ani == AH_NULL) |
890 | return HAL_ENXIO; |
891 | switch (capability) { |
892 | case 2: *result = ani->noiseImmunityLevel; break; |
893 | case 3: *result = !ani->ofdmWeakSigDetectOff; break; |
894 | case 4: *result = ani->cckWeakSigThreshold; break; |
895 | case 5: *result = ani->firstepLevel; break; |
896 | case 6: *result = ani->spurImmunityLevel; break; |
897 | } |
898 | return HAL_OK; |
899 | } |
900 | return HAL_EINVAL; |
901 | default: |
902 | return ath_hal_getcapability(ah, type, capability, result); |
903 | } |
904 | #undef MACVERSION |
905 | } |
906 | |
907 | HAL_BOOL |
908 | ar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, |
909 | uint32_t capability, uint32_t setting, HAL_STATUS *status) |
910 | { |
911 | #define N(a) (sizeof(a)/sizeof(a[0])) |
912 | struct ath_hal_5212 *ahp = AH5212(ah); |
913 | const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; |
914 | uint32_t v; |
915 | |
916 | switch (type) { |
917 | case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ |
918 | if (setting) |
919 | ahp->ah_staId1Defaults |= AR_STA_ID1_CRPT_MIC_ENABLE; |
920 | else |
921 | ahp->ah_staId1Defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE; |
922 | return AH_TRUE; |
923 | case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ |
924 | if (!pCap->halTkipMicTxRxKeySupport) |
925 | return AH_FALSE; |
926 | /* NB: true =>'s use split key cache layout */ |
927 | if (setting) |
928 | ahp->ah_miscMode &= ~AR_MISC_MODE_MIC_NEW_LOC_ENABLE; |
929 | else |
930 | ahp->ah_miscMode |= AR_MISC_MODE_MIC_NEW_LOC_ENABLE; |
931 | /* NB: write here so keys can be setup w/o a reset */ |
932 | OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); |
933 | return AH_TRUE; |
934 | case HAL_CAP_DIVERSITY: |
935 | if (ahp->ah_phyPowerOn) { |
936 | v = OS_REG_READ(ah, AR_PHY_CCK_DETECT); |
937 | if (setting) |
938 | v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; |
939 | else |
940 | v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; |
941 | OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v); |
942 | } |
943 | ahp->ah_diversity = (setting != 0); |
944 | return AH_TRUE; |
945 | case HAL_CAP_DIAG: /* hardware diagnostic support */ |
946 | /* |
947 | * NB: could split this up into virtual capabilities, |
948 | * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly |
949 | * seems worth the additional complexity. |
950 | */ |
951 | AH_PRIVATE(ah)->ah_diagreg = setting; |
952 | OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); |
953 | return AH_TRUE; |
954 | case HAL_CAP_TPC: |
955 | ahp->ah_tpcEnabled = (setting != 0); |
956 | return AH_TRUE; |
957 | case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ |
958 | if (setting) |
959 | ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; |
960 | else |
961 | ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; |
962 | return AH_TRUE; |
963 | case HAL_CAP_TPC_ACK: |
964 | case HAL_CAP_TPC_CTS: |
965 | setting += ahp->ah_txPowerIndexOffset; |
966 | if (setting > 63) |
967 | setting = 63; |
968 | if (type == HAL_CAP_TPC_ACK) { |
969 | ahp->ah_macTPC &= AR_TPC_ACK; |
970 | ahp->ah_macTPC |= MS(setting, AR_TPC_ACK); |
971 | } else { |
972 | ahp->ah_macTPC &= AR_TPC_CTS; |
973 | ahp->ah_macTPC |= MS(setting, AR_TPC_CTS); |
974 | } |
975 | OS_REG_WRITE(ah, AR_TPC, ahp->ah_macTPC); |
976 | return AH_TRUE; |
977 | case HAL_CAP_INTMIT: { /* interference mitigation */ |
978 | static const HAL_ANI_CMD cmds[] = { |
979 | HAL_ANI_PRESENT, |
980 | HAL_ANI_MODE, |
981 | HAL_ANI_NOISE_IMMUNITY_LEVEL, |
982 | HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, |
983 | HAL_ANI_CCK_WEAK_SIGNAL_THR, |
984 | HAL_ANI_FIRSTEP_LEVEL, |
985 | HAL_ANI_SPUR_IMMUNITY_LEVEL, |
986 | }; |
987 | return capability < N(cmds) ? |
988 | ar5212AniControl(ah, cmds[capability], setting) : |
989 | AH_FALSE; |
990 | } |
991 | case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ |
992 | if (pCap->halTsfAddSupport) { |
993 | if (setting) |
994 | ahp->ah_miscMode |= AR_MISC_MODE_TX_ADD_TSF; |
995 | else |
996 | ahp->ah_miscMode &= ~AR_MISC_MODE_TX_ADD_TSF; |
997 | return AH_TRUE; |
998 | } |
999 | /* fall thru... */ |
1000 | default: |
1001 | return ath_hal_setcapability(ah, type, capability, |
1002 | setting, status); |
1003 | } |
1004 | #undef N |
1005 | } |
1006 | |
1007 | HAL_BOOL |
1008 | ar5212GetDiagState(struct ath_hal *ah, int request, |
1009 | const void *args, uint32_t argsize, |
1010 | void **result, uint32_t *resultsize) |
1011 | { |
1012 | struct ath_hal_5212 *ahp = AH5212(ah); |
1013 | |
1014 | (void) ahp; |
1015 | if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) |
1016 | return AH_TRUE; |
1017 | switch (request) { |
1018 | case HAL_DIAG_EEPROM: |
1019 | case HAL_DIAG_EEPROM_EXP_11A: |
1020 | case HAL_DIAG_EEPROM_EXP_11B: |
1021 | case HAL_DIAG_EEPROM_EXP_11G: |
1022 | case HAL_DIAG_RFGAIN: |
1023 | return ath_hal_eepromDiag(ah, request, |
1024 | args, argsize, result, resultsize); |
1025 | case HAL_DIAG_RFGAIN_CURSTEP: |
1026 | *result = __DECONST(void *, ahp->ah_gainValues.currStep); |
1027 | *resultsize = (*result == AH_NULL) ? |
1028 | 0 : sizeof(GAIN_OPTIMIZATION_STEP); |
1029 | return AH_TRUE; |
1030 | case HAL_DIAG_PCDAC: |
1031 | *result = ahp->ah_pcdacTable; |
1032 | *resultsize = ahp->ah_pcdacTableSize; |
1033 | return AH_TRUE; |
1034 | case HAL_DIAG_TXRATES: |
1035 | *result = &ahp->ah_ratesArray[0]; |
1036 | *resultsize = sizeof(ahp->ah_ratesArray); |
1037 | return AH_TRUE; |
1038 | case HAL_DIAG_ANI_CURRENT: |
1039 | *result = ar5212AniGetCurrentState(ah); |
1040 | *resultsize = (*result == AH_NULL) ? |
1041 | 0 : sizeof(struct ar5212AniState); |
1042 | return AH_TRUE; |
1043 | case HAL_DIAG_ANI_STATS: |
1044 | *result = ar5212AniGetCurrentStats(ah); |
1045 | *resultsize = (*result == AH_NULL) ? |
1046 | 0 : sizeof(struct ar5212Stats); |
1047 | return AH_TRUE; |
1048 | case HAL_DIAG_ANI_CMD: |
1049 | if (argsize != 2*sizeof(uint32_t)) |
1050 | return AH_FALSE; |
1051 | ar5212AniControl(ah, ((const uint32_t *)args)[0], |
1052 | ((const uint32_t *)args)[1]); |
1053 | return AH_TRUE; |
1054 | case HAL_DIAG_ANI_PARAMS: |
1055 | /* |
1056 | * NB: We assume struct ar5212AniParams is identical |
1057 | * to HAL_ANI_PARAMS; if they diverge then we'll need |
1058 | * to handle it here |
1059 | */ |
1060 | if (argsize == 0 && args == AH_NULL) { |
1061 | struct ar5212AniState *aniState = |
1062 | ar5212AniGetCurrentState(ah); |
1063 | if (aniState == AH_NULL) |
1064 | return AH_FALSE; |
1065 | *result = __DECONST(void *, aniState->params); |
1066 | *resultsize = sizeof(struct ar5212AniParams); |
1067 | return AH_TRUE; |
1068 | } else { |
1069 | if (argsize != sizeof(struct ar5212AniParams)) |
1070 | return AH_FALSE; |
1071 | return ar5212AniSetParams(ah, args, args); |
1072 | } |
1073 | } |
1074 | return AH_FALSE; |
1075 | } |
1076 | |
1077 | /* |
1078 | * Check whether there's an in-progress NF completion. |
1079 | * |
1080 | * Returns AH_TRUE if there's a in-progress NF calibration, AH_FALSE |
1081 | * otherwise. |
1082 | */ |
1083 | HAL_BOOL |
1084 | ar5212IsNFCalInProgress(struct ath_hal *ah) |
1085 | { |
1086 | if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) |
1087 | return AH_TRUE; |
1088 | return AH_FALSE; |
1089 | } |
1090 | |
1091 | /* |
1092 | * Wait for an in-progress NF calibration to complete. |
1093 | * |
1094 | * The completion function waits "i" times 10uS. |
1095 | * It returns AH_TRUE if the NF calibration completed (or was never |
1096 | * in progress); AH_FALSE if it was still in progress after "i" checks. |
1097 | */ |
1098 | HAL_BOOL |
1099 | ar5212WaitNFCalComplete(struct ath_hal *ah, int i) |
1100 | { |
1101 | int j; |
1102 | |
1103 | if (i <= 0) |
1104 | i = 1; /* it should run at least once */ |
1105 | for (j = 0; j < i; i++) { |
1106 | if (! ar5212IsNFCalInProgress(ah)) |
1107 | return AH_TRUE; |
1108 | OS_DELAY(10); |
1109 | } |
1110 | return AH_FALSE; |
1111 | } |
1112 | |