2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2008 Atheros Communications, Inc.
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.
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.
17 * $Id: ah.c,v 1.2 2008/12/11 05:30:29 alc Exp $
22 #include "ah_internal.h"
25 /* linker set of registered chips */
26 OS_SET_DECLARE(ah_chips
, struct ath_hal_chip
);
29 * Check the set of registered chips to see if any recognize
30 * the device as one they can support.
33 ath_hal_probe(uint16_t vendorid
, uint16_t devid
)
35 struct ath_hal_chip
* const *pchip
;
37 OS_SET_FOREACH(pchip
, ah_chips
) {
38 const char *name
= (*pchip
)->probe(vendorid
, devid
);
46 * Attach detects device chip revisions, initializes the hwLayer
47 * function list, reads EEPROM information,
48 * selects reset vectors, and performs a short self test.
49 * Any failures will return an error that should cause a hardware
53 ath_hal_attach(uint16_t devid
, HAL_SOFTC sc
,
54 HAL_BUS_TAG st
, HAL_BUS_HANDLE sh
, HAL_STATUS
*error
)
56 struct ath_hal_chip
* const *pchip
;
58 OS_SET_FOREACH(pchip
, ah_chips
) {
59 struct ath_hal_chip
*chip
= *pchip
;
62 /* XXX don't have vendorid, assume atheros one works */
63 if (chip
->probe(ATHEROS_VENDOR_ID
, devid
) == AH_NULL
)
65 ah
= chip
->attach(devid
, sc
, st
, sh
, error
);
67 /* copy back private state to public area */
68 ah
->ah_devid
= AH_PRIVATE(ah
)->ah_devid
;
69 ah
->ah_subvendorid
= AH_PRIVATE(ah
)->ah_subvendorid
;
70 ah
->ah_macVersion
= AH_PRIVATE(ah
)->ah_macVersion
;
71 ah
->ah_macRev
= AH_PRIVATE(ah
)->ah_macRev
;
72 ah
->ah_phyRev
= AH_PRIVATE(ah
)->ah_phyRev
;
73 ah
->ah_analog5GhzRev
= AH_PRIVATE(ah
)->ah_analog5GhzRev
;
74 ah
->ah_analog2GhzRev
= AH_PRIVATE(ah
)->ah_analog2GhzRev
;
81 /* linker set of registered RF backends */
82 OS_SET_DECLARE(ah_rfs
, struct ath_hal_rf
);
85 * Check the set of registered RF backends to see if
86 * any recognize the device as one they can support.
89 ath_hal_rfprobe(struct ath_hal
*ah
, HAL_STATUS
*ecode
)
92 struct ath_hal_rf
* const *prf
;
94 OS_SET_FOREACH(prf
, ah_rfs
) {
95 struct ath_hal_rf
*rf
= *prf
;
99 *ecode
= HAL_ENOTSUPP
;
105 * Poll the register looking for a specific value.
108 ath_hal_wait(struct ath_hal
*ah
, u_int reg
, uint32_t mask
, uint32_t val
)
110 #define AH_TIMEOUT 1000
113 for (i
= 0; i
< AH_TIMEOUT
; i
++) {
114 if ((OS_REG_READ(ah
, reg
) & mask
) == val
)
118 HALDEBUG(ah
, HAL_DEBUG_REGIO
| HAL_DEBUG_PHYIO
,
119 "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
120 __func__
, reg
, OS_REG_READ(ah
, reg
), mask
, val
);
126 * Reverse the bits starting at the low bit for a value of
130 ath_hal_reverseBits(uint32_t val
, uint32_t n
)
135 for (i
= 0, retval
= 0; i
< n
; i
++) {
136 retval
= (retval
<< 1) | (val
& 1);
143 * Compute the time to transmit a frame of length frameLen bytes
144 * using the specified rate, phy, and short preamble setting.
147 ath_hal_computetxtime(struct ath_hal
*ah
,
148 const HAL_RATE_TABLE
*rates
, uint32_t frameLen
, uint16_t rateix
,
149 HAL_BOOL shortPreamble
)
151 uint32_t bitsPerSymbol
, numBits
, numSymbols
, phyTime
, txTime
;
154 kbps
= rates
->info
[rateix
].rateKbps
;
156 * index can be invalid duting dynamic Turbo transitions.
158 if(kbps
== 0) return 0;
159 switch (rates
->info
[rateix
].phy
) {
161 case IEEE80211_T_CCK
:
162 #define CCK_SIFS_TIME 10
163 #define CCK_PREAMBLE_BITS 144
164 #define CCK_PLCP_BITS 48
165 phyTime
= CCK_PREAMBLE_BITS
+ CCK_PLCP_BITS
;
166 if (shortPreamble
&& rates
->info
[rateix
].shortPreamble
)
168 numBits
= frameLen
<< 3;
169 txTime
= CCK_SIFS_TIME
+ phyTime
170 + ((numBits
* 1000)/kbps
);
173 #undef CCK_PREAMBLE_BITS
176 case IEEE80211_T_OFDM
:
177 #define OFDM_SIFS_TIME 16
178 #define OFDM_PREAMBLE_TIME 20
179 #define OFDM_PLCP_BITS 22
180 #define OFDM_SYMBOL_TIME 4
182 #define OFDM_SIFS_TIME_HALF 32
183 #define OFDM_PREAMBLE_TIME_HALF 40
184 #define OFDM_PLCP_BITS_HALF 22
185 #define OFDM_SYMBOL_TIME_HALF 8
187 #define OFDM_SIFS_TIME_QUARTER 64
188 #define OFDM_PREAMBLE_TIME_QUARTER 80
189 #define OFDM_PLCP_BITS_QUARTER 22
190 #define OFDM_SYMBOL_TIME_QUARTER 16
192 if (AH_PRIVATE(ah
)->ah_curchan
&&
193 IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah
)->ah_curchan
)) {
194 bitsPerSymbol
= (kbps
* OFDM_SYMBOL_TIME_QUARTER
) / 1000;
195 HALASSERT(bitsPerSymbol
!= 0);
197 numBits
= OFDM_PLCP_BITS
+ (frameLen
<< 3);
198 numSymbols
= howmany(numBits
, bitsPerSymbol
);
199 txTime
= OFDM_SIFS_TIME_QUARTER
200 + OFDM_PREAMBLE_TIME_QUARTER
201 + (numSymbols
* OFDM_SYMBOL_TIME_QUARTER
);
202 } else if (AH_PRIVATE(ah
)->ah_curchan
&&
203 IS_CHAN_HALF_RATE(AH_PRIVATE(ah
)->ah_curchan
)) {
204 bitsPerSymbol
= (kbps
* OFDM_SYMBOL_TIME_HALF
) / 1000;
205 HALASSERT(bitsPerSymbol
!= 0);
207 numBits
= OFDM_PLCP_BITS
+ (frameLen
<< 3);
208 numSymbols
= howmany(numBits
, bitsPerSymbol
);
209 txTime
= OFDM_SIFS_TIME_HALF
+
210 OFDM_PREAMBLE_TIME_HALF
211 + (numSymbols
* OFDM_SYMBOL_TIME_HALF
);
212 } else { /* full rate channel */
213 bitsPerSymbol
= (kbps
* OFDM_SYMBOL_TIME
) / 1000;
214 HALASSERT(bitsPerSymbol
!= 0);
216 numBits
= OFDM_PLCP_BITS
+ (frameLen
<< 3);
217 numSymbols
= howmany(numBits
, bitsPerSymbol
);
218 txTime
= OFDM_SIFS_TIME
+ OFDM_PREAMBLE_TIME
219 + (numSymbols
* OFDM_SYMBOL_TIME
);
223 #undef OFDM_SIFS_TIME
224 #undef OFDM_PREAMBLE_TIME
225 #undef OFDM_PLCP_BITS
226 #undef OFDM_SYMBOL_TIME
228 case IEEE80211_T_TURBO
:
229 #define TURBO_SIFS_TIME 8
230 #define TURBO_PREAMBLE_TIME 14
231 #define TURBO_PLCP_BITS 22
232 #define TURBO_SYMBOL_TIME 4
233 /* we still save OFDM rates in kbps - so double them */
234 bitsPerSymbol
= ((kbps
<< 1) * TURBO_SYMBOL_TIME
) / 1000;
235 HALASSERT(bitsPerSymbol
!= 0);
237 numBits
= TURBO_PLCP_BITS
+ (frameLen
<< 3);
238 numSymbols
= howmany(numBits
, bitsPerSymbol
);
239 txTime
= TURBO_SIFS_TIME
+ TURBO_PREAMBLE_TIME
240 + (numSymbols
* TURBO_SYMBOL_TIME
);
242 #undef TURBO_SIFS_TIME
243 #undef TURBO_PREAMBLE_TIME
244 #undef TURBO_PLCP_BITS
245 #undef TURBO_SYMBOL_TIME
248 HALDEBUG(ah
, HAL_DEBUG_PHYIO
,
249 "%s: unknown phy %u (rate ix %u)\n",
250 __func__
, rates
->info
[rateix
].phy
, rateix
);
258 mapgsm(u_int freq
, u_int flags
)
261 if (flags
& CHANNEL_QUARTER
)
263 else if (flags
& CHANNEL_HALF
)
267 return (freq
- 24220) / 5;
271 mappsb(u_int freq
, u_int flags
)
273 return ((freq
* 10) + (((freq
% 5) == 2) ? 5 : 0) - 49400) / 5;
277 * Convert GHz frequency to IEEE channel number.
280 ath_hal_mhz2ieee(struct ath_hal
*ah
, u_int freq
, u_int flags
)
282 if (flags
& CHANNEL_2GHZ
) { /* 2GHz band */
286 if (ath_hal_isgsmsku(ah
))
287 return mapgsm(freq
, flags
);
288 return ((int)freq
- 2407) / 5;
290 return 15 + ((freq
- 2512) / 20);
291 } else if (flags
& CHANNEL_5GHZ
) {/* 5Ghz band */
292 if (ath_hal_ispublicsafetysku(ah
) &&
293 IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq
)) {
294 return mappsb(freq
, flags
);
295 } else if ((flags
& CHANNEL_A
) && (freq
<= 5000)) {
296 return (freq
- 4000) / 5;
298 return (freq
- 5000) / 5;
300 } else { /* either, guess */
304 if (ath_hal_isgsmsku(ah
))
305 return mapgsm(freq
, flags
);
306 return ((int)freq
- 2407) / 5;
309 if (ath_hal_ispublicsafetysku(ah
) &&
310 IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq
)) {
311 return mappsb(freq
, flags
);
312 } else if (freq
> 4900) {
313 return (freq
- 4000) / 5;
315 return 15 + ((freq
- 2512) / 20);
318 return (freq
- 5000) / 5;
323 WIRELESS_MODE_11a
= 0,
324 WIRELESS_MODE_TURBO
= 1,
325 WIRELESS_MODE_11b
= 2,
326 WIRELESS_MODE_11g
= 3,
327 WIRELESS_MODE_108g
= 4,
333 ath_hal_chan2wmode(struct ath_hal
*ah
, const HAL_CHANNEL
*chan
)
335 if (IS_CHAN_CCK(chan
))
336 return WIRELESS_MODE_11b
;
338 return WIRELESS_MODE_11g
;
339 if (IS_CHAN_108G(chan
))
340 return WIRELESS_MODE_108g
;
341 if (IS_CHAN_TURBO(chan
))
342 return WIRELESS_MODE_TURBO
;
343 return WIRELESS_MODE_11a
;
347 * Convert between microseconds and core system clocks.
349 /* 11a Turbo 11b 11g 108g */
350 static const uint8_t CLOCK_RATE
[] = { 40, 80, 22, 44, 88 };
353 ath_hal_mac_clks(struct ath_hal
*ah
, u_int usecs
)
355 const HAL_CHANNEL
*c
= (const HAL_CHANNEL
*) AH_PRIVATE(ah
)->ah_curchan
;
358 /* NB: ah_curchan may be null when called attach time */
360 clks
= usecs
* CLOCK_RATE
[ath_hal_chan2wmode(ah
, c
)];
363 else if (IS_CHAN_HALF_RATE(c
))
365 else if (IS_CHAN_QUARTER_RATE(c
))
368 clks
= usecs
* CLOCK_RATE
[WIRELESS_MODE_11b
];
373 ath_hal_mac_usec(struct ath_hal
*ah
, u_int clks
)
375 const HAL_CHANNEL
*c
= (const HAL_CHANNEL
*) AH_PRIVATE(ah
)->ah_curchan
;
378 /* NB: ah_curchan may be null when called attach time */
380 usec
= clks
/ CLOCK_RATE
[ath_hal_chan2wmode(ah
, c
)];
383 else if (IS_CHAN_HALF_RATE(c
))
385 else if (IS_CHAN_QUARTER_RATE(c
))
388 usec
= clks
/ CLOCK_RATE
[WIRELESS_MODE_11b
];
393 * Setup a h/w rate table's reverse lookup table and
394 * fill in ack durations. This routine is called for
395 * each rate table returned through the ah_getRateTable
396 * method. The reverse lookup tables are assumed to be
397 * initialized to zero (or at least the first entry).
398 * We use this as a key that indicates whether or not
399 * we've previously setup the reverse lookup table.
401 * XXX not reentrant, but shouldn't matter
404 ath_hal_setupratetable(struct ath_hal
*ah
, HAL_RATE_TABLE
*rt
)
406 #define N(a) (sizeof(a)/sizeof(a[0]))
409 if (rt
->rateCodeToIndex
[0] != 0) /* already setup */
411 for (i
= 0; i
< N(rt
->rateCodeToIndex
); i
++)
412 rt
->rateCodeToIndex
[i
] = (uint8_t) -1;
413 for (i
= 0; i
< rt
->rateCount
; i
++) {
414 uint8_t code
= rt
->info
[i
].rateCode
;
415 uint8_t cix
= rt
->info
[i
].controlRate
;
417 HALASSERT(code
< N(rt
->rateCodeToIndex
));
418 rt
->rateCodeToIndex
[code
] = i
;
419 HALASSERT((code
| rt
->info
[i
].shortPreamble
) <
420 N(rt
->rateCodeToIndex
));
421 rt
->rateCodeToIndex
[code
| rt
->info
[i
].shortPreamble
] = i
;
423 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
424 * depends on whether they are marked as basic rates;
425 * the static tables are setup with an 11b-compatible
426 * 2Mb/s rate which will work but is suboptimal
428 rt
->info
[i
].lpAckDuration
= ath_hal_computetxtime(ah
, rt
,
429 WLAN_CTRL_FRAME_SIZE
, cix
, AH_FALSE
);
430 rt
->info
[i
].spAckDuration
= ath_hal_computetxtime(ah
, rt
,
431 WLAN_CTRL_FRAME_SIZE
, cix
, AH_TRUE
);
437 ath_hal_getcapability(struct ath_hal
*ah
, HAL_CAPABILITY_TYPE type
,
438 uint32_t capability
, uint32_t *result
)
440 const HAL_CAPABILITIES
*pCap
= &AH_PRIVATE(ah
)->ah_caps
;
443 case HAL_CAP_REG_DMN
: /* regulatory domain */
444 *result
= AH_PRIVATE(ah
)->ah_currentRD
;
446 case HAL_CAP_CIPHER
: /* cipher handled in hardware */
447 case HAL_CAP_TKIP_MIC
: /* handle TKIP MIC in hardware */
449 case HAL_CAP_TKIP_SPLIT
: /* hardware TKIP uses split keys */
451 case HAL_CAP_PHYCOUNTERS
: /* hardware PHY error counters */
452 return pCap
->halHwPhyCounterSupport
? HAL_OK
: HAL_ENXIO
;
453 case HAL_CAP_WME_TKIPMIC
: /* hardware can do TKIP MIC when WMM is turned on */
455 case HAL_CAP_DIVERSITY
: /* hardware supports fast diversity */
457 case HAL_CAP_KEYCACHE_SIZE
: /* hardware key cache size */
458 *result
= pCap
->halKeyCacheSize
;
460 case HAL_CAP_NUM_TXQUEUES
: /* number of hardware tx queues */
461 *result
= pCap
->halTotalQueues
;
463 case HAL_CAP_VEOL
: /* hardware supports virtual EOL */
464 return pCap
->halVEOLSupport
? HAL_OK
: HAL_ENOTSUPP
;
465 case HAL_CAP_PSPOLL
: /* hardware PS-Poll support works */
466 return pCap
->halPSPollBroken
? HAL_ENOTSUPP
: HAL_OK
;
467 case HAL_CAP_COMPRESSION
:
468 return pCap
->halCompressSupport
? HAL_OK
: HAL_ENOTSUPP
;
470 return pCap
->halBurstSupport
? HAL_OK
: HAL_ENOTSUPP
;
471 case HAL_CAP_FASTFRAME
:
472 return pCap
->halFastFramesSupport
? HAL_OK
: HAL_ENOTSUPP
;
473 case HAL_CAP_DIAG
: /* hardware diagnostic support */
474 *result
= AH_PRIVATE(ah
)->ah_diagreg
;
476 case HAL_CAP_TXPOW
: /* global tx power limit */
477 switch (capability
) {
478 case 0: /* facility is supported */
480 case 1: /* current limit */
481 *result
= AH_PRIVATE(ah
)->ah_powerLimit
;
483 case 2: /* current max tx power */
484 *result
= AH_PRIVATE(ah
)->ah_maxPowerLevel
;
486 case 3: /* scale factor */
487 *result
= AH_PRIVATE(ah
)->ah_tpScale
;
491 case HAL_CAP_BSSIDMASK
: /* hardware supports bssid mask */
492 return pCap
->halBssIdMaskSupport
? HAL_OK
: HAL_ENOTSUPP
;
493 case HAL_CAP_MCAST_KEYSRCH
: /* multicast frame keycache search */
494 return pCap
->halMcastKeySrchSupport
? HAL_OK
: HAL_ENOTSUPP
;
495 case HAL_CAP_TSF_ADJUST
: /* hardware has beacon tsf adjust */
497 case HAL_CAP_RFSILENT
: /* rfsilent support */
498 switch (capability
) {
499 case 0: /* facility is supported */
500 return pCap
->halRfSilentSupport
? HAL_OK
: HAL_ENOTSUPP
;
501 case 1: /* current setting */
502 return AH_PRIVATE(ah
)->ah_rfkillEnabled
?
503 HAL_OK
: HAL_ENOTSUPP
;
504 case 2: /* rfsilent config */
505 *result
= AH_PRIVATE(ah
)->ah_rfsilent
;
510 #ifdef AH_SUPPORT_11D
515 case HAL_CAP_RXORN_FATAL
: /* HAL_INT_RXORN treated as fatal */
516 return AH_PRIVATE(ah
)->ah_rxornIsFatal
? HAL_OK
: HAL_ENOTSUPP
;
518 return pCap
->halHTSupport
? HAL_OK
: HAL_ENOTSUPP
;
519 case HAL_CAP_TX_CHAINMASK
: /* mask of TX chains supported */
520 *result
= pCap
->halTxChainMask
;
522 case HAL_CAP_RX_CHAINMASK
: /* mask of RX chains supported */
523 *result
= pCap
->halRxChainMask
;
525 case HAL_CAP_RXTSTAMP_PREC
: /* rx desc tstamp precision (bits) */
526 *result
= pCap
->halTstampPrecision
;
534 ath_hal_setcapability(struct ath_hal
*ah
, HAL_CAPABILITY_TYPE type
,
535 uint32_t capability
, uint32_t setting
, HAL_STATUS
*status
)
540 switch (capability
) {
542 if (setting
<= HAL_TP_SCALE_MIN
) {
543 AH_PRIVATE(ah
)->ah_tpScale
= setting
;
549 case HAL_CAP_RFSILENT
: /* rfsilent support */
551 * NB: allow even if halRfSilentSupport is false
552 * in case the EEPROM is misprogrammed.
554 switch (capability
) {
555 case 1: /* current setting */
556 AH_PRIVATE(ah
)->ah_rfkillEnabled
= (setting
!= 0);
558 case 2: /* rfsilent config */
559 /* XXX better done per-chip for validation? */
560 AH_PRIVATE(ah
)->ah_rfsilent
= setting
;
564 case HAL_CAP_REG_DMN
: /* regulatory domain */
565 AH_PRIVATE(ah
)->ah_currentRD
= setting
;
567 case HAL_CAP_RXORN_FATAL
: /* HAL_INT_RXORN treated as fatal */
568 AH_PRIVATE(ah
)->ah_rxornIsFatal
= setting
;
574 *status
= HAL_EINVAL
;
579 * Common support for getDiagState method.
583 ath_hal_getregdump(struct ath_hal
*ah
, const HAL_REGRANGE
*regs
,
584 void *dstbuf
, int space
)
586 uint32_t *dp
= dstbuf
;
589 for (i
= 0; space
>= 2*sizeof(uint32_t); i
++) {
590 u_int r
= regs
[i
].start
;
591 u_int e
= regs
[i
].end
;
593 space
-= sizeof(uint32_t);
595 *dp
++ = OS_REG_READ(ah
, r
);
596 r
+= sizeof(uint32_t);
597 space
-= sizeof(uint32_t);
598 } while (r
<= e
&& space
>= sizeof(uint32_t));
600 return (char *) dp
- (char *) dstbuf
;
604 ath_hal_getdiagstate(struct ath_hal
*ah
, int request
,
605 const void *args
, uint32_t argsize
,
606 void **result
, uint32_t *resultsize
)
610 *result
= &AH_PRIVATE(ah
)->ah_devid
;
611 *resultsize
= sizeof(HAL_REVS
);
614 *resultsize
= ath_hal_getregdump(ah
, args
, *result
,*resultsize
);
616 case HAL_DIAG_FATALERR
:
617 *result
= &AH_PRIVATE(ah
)->ah_fatalState
[0];
618 *resultsize
= sizeof(AH_PRIVATE(ah
)->ah_fatalState
);
620 case HAL_DIAG_EEREAD
:
621 if (argsize
!= sizeof(uint16_t))
623 if (!ath_hal_eepromRead(ah
, *(const uint16_t *)args
, *result
))
625 *resultsize
= sizeof(uint16_t);
627 #ifdef AH_PRIVATE_DIAG
628 case HAL_DIAG_SETKEY
: {
629 const HAL_DIAG_KEYVAL
*dk
;
631 if (argsize
!= sizeof(HAL_DIAG_KEYVAL
))
633 dk
= (const HAL_DIAG_KEYVAL
*)args
;
634 return ah
->ah_setKeyCacheEntry(ah
, dk
->dk_keyix
,
635 &dk
->dk_keyval
, dk
->dk_mac
, dk
->dk_xor
);
637 case HAL_DIAG_RESETKEY
:
638 if (argsize
!= sizeof(uint16_t))
640 return ah
->ah_resetKeyCacheEntry(ah
, *(const uint16_t *)args
);
641 #ifdef AH_SUPPORT_WRITE_EEPROM
642 case HAL_DIAG_EEWRITE
: {
643 const HAL_DIAG_EEVAL
*ee
;
644 if (argsize
!= sizeof(HAL_DIAG_EEVAL
))
646 ee
= (const HAL_DIAG_EEVAL
*)args
;
647 return ath_hal_eepromWrite(ah
, ee
->ee_off
, ee
->ee_data
);
649 #endif /* AH_SUPPORT_WRITE_EEPROM */
650 #endif /* AH_PRIVATE_DIAG */
651 case HAL_DIAG_11NCOMPAT
:
653 *resultsize
= sizeof(uint32_t);
654 *((uint32_t *)(*result
)) =
655 AH_PRIVATE(ah
)->ah_11nCompat
;
656 } else if (argsize
== sizeof(uint32_t)) {
657 AH_PRIVATE(ah
)->ah_11nCompat
= *(const uint32_t *)args
;
666 * Set the properties of the tx queue with the parameters
670 ath_hal_setTxQProps(struct ath_hal
*ah
,
671 HAL_TX_QUEUE_INFO
*qi
, const HAL_TXQ_INFO
*qInfo
)
675 if (qi
->tqi_type
== HAL_TX_QUEUE_INACTIVE
) {
676 HALDEBUG(ah
, HAL_DEBUG_TXQUEUE
,
677 "%s: inactive queue\n", __func__
);
680 /* XXX validate parameters */
681 qi
->tqi_ver
= qInfo
->tqi_ver
;
682 qi
->tqi_subtype
= qInfo
->tqi_subtype
;
683 qi
->tqi_qflags
= qInfo
->tqi_qflags
;
684 qi
->tqi_priority
= qInfo
->tqi_priority
;
685 if (qInfo
->tqi_aifs
!= HAL_TXQ_USEDEFAULT
)
686 qi
->tqi_aifs
= AH_MIN(qInfo
->tqi_aifs
, 255);
688 qi
->tqi_aifs
= INIT_AIFS
;
689 if (qInfo
->tqi_cwmin
!= HAL_TXQ_USEDEFAULT
) {
690 cw
= AH_MIN(qInfo
->tqi_cwmin
, 1024);
691 /* make sure that the CWmin is of the form (2^n - 1) */
693 while (qi
->tqi_cwmin
< cw
)
694 qi
->tqi_cwmin
= (qi
->tqi_cwmin
<< 1) | 1;
696 qi
->tqi_cwmin
= qInfo
->tqi_cwmin
;
697 if (qInfo
->tqi_cwmax
!= HAL_TXQ_USEDEFAULT
) {
698 cw
= AH_MIN(qInfo
->tqi_cwmax
, 1024);
699 /* make sure that the CWmax is of the form (2^n - 1) */
701 while (qi
->tqi_cwmax
< cw
)
702 qi
->tqi_cwmax
= (qi
->tqi_cwmax
<< 1) | 1;
704 qi
->tqi_cwmax
= INIT_CWMAX
;
705 /* Set retry limit values */
706 if (qInfo
->tqi_shretry
!= 0)
707 qi
->tqi_shretry
= AH_MIN(qInfo
->tqi_shretry
, 15);
709 qi
->tqi_shretry
= INIT_SH_RETRY
;
710 if (qInfo
->tqi_lgretry
!= 0)
711 qi
->tqi_lgretry
= AH_MIN(qInfo
->tqi_lgretry
, 15);
713 qi
->tqi_lgretry
= INIT_LG_RETRY
;
714 qi
->tqi_cbrPeriod
= qInfo
->tqi_cbrPeriod
;
715 qi
->tqi_cbrOverflowLimit
= qInfo
->tqi_cbrOverflowLimit
;
716 qi
->tqi_burstTime
= qInfo
->tqi_burstTime
;
717 qi
->tqi_readyTime
= qInfo
->tqi_readyTime
;
719 switch (qInfo
->tqi_subtype
) {
721 if (qi
->tqi_type
== HAL_TX_QUEUE_DATA
)
722 qi
->tqi_intFlags
= HAL_TXQ_USE_LOCKOUT_BKOFF_DIS
;
725 break; /* NB: silence compiler */
731 ath_hal_getTxQProps(struct ath_hal
*ah
,
732 HAL_TXQ_INFO
*qInfo
, const HAL_TX_QUEUE_INFO
*qi
)
734 if (qi
->tqi_type
== HAL_TX_QUEUE_INACTIVE
) {
735 HALDEBUG(ah
, HAL_DEBUG_TXQUEUE
,
736 "%s: inactive queue\n", __func__
);
740 qInfo
->tqi_qflags
= qi
->tqi_qflags
;
741 qInfo
->tqi_ver
= qi
->tqi_ver
;
742 qInfo
->tqi_subtype
= qi
->tqi_subtype
;
743 qInfo
->tqi_qflags
= qi
->tqi_qflags
;
744 qInfo
->tqi_priority
= qi
->tqi_priority
;
745 qInfo
->tqi_aifs
= qi
->tqi_aifs
;
746 qInfo
->tqi_cwmin
= qi
->tqi_cwmin
;
747 qInfo
->tqi_cwmax
= qi
->tqi_cwmax
;
748 qInfo
->tqi_shretry
= qi
->tqi_shretry
;
749 qInfo
->tqi_lgretry
= qi
->tqi_lgretry
;
750 qInfo
->tqi_cbrPeriod
= qi
->tqi_cbrPeriod
;
751 qInfo
->tqi_cbrOverflowLimit
= qi
->tqi_cbrOverflowLimit
;
752 qInfo
->tqi_burstTime
= qi
->tqi_burstTime
;
753 qInfo
->tqi_readyTime
= qi
->tqi_readyTime
;
757 /* 11a Turbo 11b 11g 108g */
758 static const int16_t NOISE_FLOOR
[] = { -96, -93, -98, -96, -93 };
761 * Read the current channel noise floor and return.
762 * If nf cal hasn't finished, channel noise floor should be 0
763 * and we return a nominal value based on band and frequency.
765 * NB: This is a private routine used by per-chip code to
766 * implement the ah_getChanNoise method.
769 ath_hal_getChanNoise(struct ath_hal
*ah
, HAL_CHANNEL
*chan
)
771 HAL_CHANNEL_INTERNAL
*ichan
;
773 ichan
= ath_hal_checkchannel(ah
, chan
);
774 if (ichan
== AH_NULL
) {
775 HALDEBUG(ah
, HAL_DEBUG_NFCAL
,
776 "%s: invalid channel %u/0x%x; no mapping\n",
777 __func__
, chan
->channel
, chan
->channelFlags
);
780 if (ichan
->rawNoiseFloor
== 0) {
781 WIRELESS_MODE mode
= ath_hal_chan2wmode(ah
, chan
);
783 HALASSERT(mode
< WIRELESS_MODE_MAX
);
784 return NOISE_FLOOR
[mode
] + ath_hal_getNfAdjust(ah
, ichan
);
786 return ichan
->rawNoiseFloor
+ ichan
->noiseFloorAdjust
;
790 * Process all valid raw noise floors into the dBm noise floor values.
791 * Though our device has no reference for a dBm noise floor, we perform
792 * a relative minimization of NF's based on the lowest NF found across a
796 ath_hal_process_noisefloor(struct ath_hal
*ah
)
798 HAL_CHANNEL_INTERNAL
*c
;
799 int16_t correct2
, correct5
;
800 int16_t lowest2
, lowest5
;
804 * Find the lowest 2GHz and 5GHz noise floor values after adjusting
805 * for statistically recorded NF/channel deviation.
807 correct2
= lowest2
= 0;
808 correct5
= lowest5
= 0;
809 for (i
= 0; i
< AH_PRIVATE(ah
)->ah_nchan
; i
++) {
813 c
= &AH_PRIVATE(ah
)->ah_channels
[i
];
814 if (c
->rawNoiseFloor
>= 0)
816 mode
= ath_hal_chan2wmode(ah
, (HAL_CHANNEL
*) c
);
817 HALASSERT(mode
< WIRELESS_MODE_MAX
);
818 nf
= c
->rawNoiseFloor
+ NOISE_FLOOR
[mode
] +
819 ath_hal_getNfAdjust(ah
, c
);
820 if (IS_CHAN_5GHZ(c
)) {
823 correct5
= NOISE_FLOOR
[mode
] -
824 (c
->rawNoiseFloor
+ ath_hal_getNfAdjust(ah
, c
));
829 correct2
= NOISE_FLOOR
[mode
] -
830 (c
->rawNoiseFloor
+ ath_hal_getNfAdjust(ah
, c
));
835 /* Correct the channels to reach the expected NF value */
836 for (i
= 0; i
< AH_PRIVATE(ah
)->ah_nchan
; i
++) {
837 c
= &AH_PRIVATE(ah
)->ah_channels
[i
];
838 if (c
->rawNoiseFloor
>= 0)
840 /* Apply correction factor */
841 c
->noiseFloorAdjust
= ath_hal_getNfAdjust(ah
, c
) +
842 (IS_CHAN_5GHZ(c
) ? correct5
: correct2
);
843 HALDEBUG(ah
, HAL_DEBUG_NFCAL
, "%u/0x%x raw nf %d adjust %d\n",
844 c
->channel
, c
->channelFlags
, c
->rawNoiseFloor
,
845 c
->noiseFloorAdjust
);
850 * INI support routines.
854 ath_hal_ini_write(struct ath_hal
*ah
, const HAL_INI_ARRAY
*ia
,
859 for (r
= 0; r
< ia
->rows
; r
++) {
860 OS_REG_WRITE(ah
, HAL_INI_VAL(ia
, r
, 0),
861 HAL_INI_VAL(ia
, r
, col
));
868 ath_hal_ini_bank_setup(uint32_t data
[], const HAL_INI_ARRAY
*ia
, int col
)
872 for (r
= 0; r
< ia
->rows
; r
++)
873 data
[r
] = HAL_INI_VAL(ia
, r
, col
);
877 ath_hal_ini_bank_write(struct ath_hal
*ah
, const HAL_INI_ARRAY
*ia
,
878 const uint32_t data
[], int regWr
)
882 for (r
= 0; r
< ia
->rows
; r
++) {
883 OS_REG_WRITE(ah
, HAL_INI_VAL(ia
, r
, 0), data
[r
]);