]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/ath/ath_hal/ah.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / ath / ath_hal / ah.c
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  * $FreeBSD$
18  */
19 #include "opt_ah.h"
20
21 #include "ah.h"
22 #include "ah_internal.h"
23 #include "ah_devid.h"
24
25 /* linker set of registered chips */
26 OS_SET_DECLARE(ah_chips, struct ath_hal_chip);
27
28 /*
29  * Check the set of registered chips to see if any recognize
30  * the device as one they can support.
31  */
32 const char*
33 ath_hal_probe(uint16_t vendorid, uint16_t devid)
34 {
35         struct ath_hal_chip * const *pchip;
36
37         OS_SET_FOREACH(pchip, ah_chips) {
38                 const char *name = (*pchip)->probe(vendorid, devid);
39                 if (name != AH_NULL)
40                         return name;
41         }
42         return AH_NULL;
43 }
44
45 /*
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
50  * disable.
51  */
52 struct ath_hal*
53 ath_hal_attach(uint16_t devid, HAL_SOFTC sc,
54         HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *error)
55 {
56         struct ath_hal_chip * const *pchip;
57
58         OS_SET_FOREACH(pchip, ah_chips) {
59                 struct ath_hal_chip *chip = *pchip;
60                 struct ath_hal *ah;
61
62                 /* XXX don't have vendorid, assume atheros one works */
63                 if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL)
64                         continue;
65                 ah = chip->attach(devid, sc, st, sh, error);
66                 if (ah != AH_NULL) {
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;
75                         return ah;
76                 }
77         }
78         return AH_NULL;
79 }
80
81 /* linker set of registered RF backends */
82 OS_SET_DECLARE(ah_rfs, struct ath_hal_rf);
83
84 /*
85  * Check the set of registered RF backends to see if
86  * any recognize the device as one they can support.
87  */
88 struct ath_hal_rf *
89 ath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode)
90 {
91         struct ath_hal_rf * const *prf;
92
93         OS_SET_FOREACH(prf, ah_rfs) {
94                 struct ath_hal_rf *rf = *prf;
95                 if (rf->probe(ah))
96                         return rf;
97         }
98         *ecode = HAL_ENOTSUPP;
99         return AH_NULL;
100 }
101
102 /*
103  * Poll the register looking for a specific value.
104  */
105 HAL_BOOL
106 ath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val)
107 {
108 #define AH_TIMEOUT      1000
109         int i;
110
111         for (i = 0; i < AH_TIMEOUT; i++) {
112                 if ((OS_REG_READ(ah, reg) & mask) == val)
113                         return AH_TRUE;
114                 OS_DELAY(10);
115         }
116         HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO,
117             "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
118             __func__, reg, OS_REG_READ(ah, reg), mask, val);
119         return AH_FALSE;
120 #undef AH_TIMEOUT
121 }
122
123 /*
124  * Reverse the bits starting at the low bit for a value of
125  * bit_count in size
126  */
127 uint32_t
128 ath_hal_reverseBits(uint32_t val, uint32_t n)
129 {
130         uint32_t retval;
131         int i;
132
133         for (i = 0, retval = 0; i < n; i++) {
134                 retval = (retval << 1) | (val & 1);
135                 val >>= 1;
136         }
137         return retval;
138 }
139
140 /*
141  * Compute the time to transmit a frame of length frameLen bytes
142  * using the specified rate, phy, and short preamble setting.
143  */
144 uint16_t
145 ath_hal_computetxtime(struct ath_hal *ah,
146         const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix,
147         HAL_BOOL shortPreamble)
148 {
149         uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
150         uint32_t kbps;
151
152         kbps = rates->info[rateix].rateKbps;
153         /*
154          * index can be invalid duting dynamic Turbo transitions. 
155          */
156         if(kbps == 0) return 0;
157         switch (rates->info[rateix].phy) {
158
159         case IEEE80211_T_CCK:
160 #define CCK_SIFS_TIME        10
161 #define CCK_PREAMBLE_BITS   144
162 #define CCK_PLCP_BITS        48
163                 phyTime         = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
164                 if (shortPreamble && rates->info[rateix].shortPreamble)
165                         phyTime >>= 1;
166                 numBits         = frameLen << 3;
167                 txTime          = CCK_SIFS_TIME + phyTime
168                                 + ((numBits * 1000)/kbps);
169                 break;
170 #undef CCK_SIFS_TIME
171 #undef CCK_PREAMBLE_BITS
172 #undef CCK_PLCP_BITS
173
174         case IEEE80211_T_OFDM:
175 #define OFDM_SIFS_TIME        16
176 #define OFDM_PREAMBLE_TIME    20
177 #define OFDM_PLCP_BITS        22
178 #define OFDM_SYMBOL_TIME       4
179
180 #define OFDM_SIFS_TIME_HALF     32
181 #define OFDM_PREAMBLE_TIME_HALF 40
182 #define OFDM_PLCP_BITS_HALF     22
183 #define OFDM_SYMBOL_TIME_HALF   8
184
185 #define OFDM_SIFS_TIME_QUARTER          64
186 #define OFDM_PREAMBLE_TIME_QUARTER      80
187 #define OFDM_PLCP_BITS_QUARTER          22
188 #define OFDM_SYMBOL_TIME_QUARTER        16
189
190                 if (AH_PRIVATE(ah)->ah_curchan && 
191                         IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan)) {
192                         bitsPerSymbol   = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
193                         HALASSERT(bitsPerSymbol != 0);
194
195                         numBits         = OFDM_PLCP_BITS + (frameLen << 3);
196                         numSymbols      = howmany(numBits, bitsPerSymbol);
197                         txTime          = OFDM_SIFS_TIME_QUARTER 
198                                                 + OFDM_PREAMBLE_TIME_QUARTER
199                                         + (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
200                 } else if (AH_PRIVATE(ah)->ah_curchan &&
201                                 IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) {
202                         bitsPerSymbol   = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
203                         HALASSERT(bitsPerSymbol != 0);
204
205                         numBits         = OFDM_PLCP_BITS + (frameLen << 3);
206                         numSymbols      = howmany(numBits, bitsPerSymbol);
207                         txTime          = OFDM_SIFS_TIME_HALF + 
208                                                 OFDM_PREAMBLE_TIME_HALF
209                                         + (numSymbols * OFDM_SYMBOL_TIME_HALF);
210                 } else { /* full rate channel */
211                         bitsPerSymbol   = (kbps * OFDM_SYMBOL_TIME) / 1000;
212                         HALASSERT(bitsPerSymbol != 0);
213
214                         numBits         = OFDM_PLCP_BITS + (frameLen << 3);
215                         numSymbols      = howmany(numBits, bitsPerSymbol);
216                         txTime          = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME
217                                         + (numSymbols * OFDM_SYMBOL_TIME);
218                 }
219                 break;
220
221 #undef OFDM_SIFS_TIME
222 #undef OFDM_PREAMBLE_TIME
223 #undef OFDM_PLCP_BITS
224 #undef OFDM_SYMBOL_TIME
225
226         case IEEE80211_T_TURBO:
227 #define TURBO_SIFS_TIME         8
228 #define TURBO_PREAMBLE_TIME    14
229 #define TURBO_PLCP_BITS        22
230 #define TURBO_SYMBOL_TIME       4
231                 /* we still save OFDM rates in kbps - so double them */
232                 bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000;
233                 HALASSERT(bitsPerSymbol != 0);
234
235                 numBits       = TURBO_PLCP_BITS + (frameLen << 3);
236                 numSymbols    = howmany(numBits, bitsPerSymbol);
237                 txTime        = TURBO_SIFS_TIME + TURBO_PREAMBLE_TIME
238                               + (numSymbols * TURBO_SYMBOL_TIME);
239                 break;
240 #undef TURBO_SIFS_TIME
241 #undef TURBO_PREAMBLE_TIME
242 #undef TURBO_PLCP_BITS
243 #undef TURBO_SYMBOL_TIME
244
245         default:
246                 HALDEBUG(ah, HAL_DEBUG_PHYIO,
247                     "%s: unknown phy %u (rate ix %u)\n",
248                     __func__, rates->info[rateix].phy, rateix);
249                 txTime = 0;
250                 break;
251         }
252         return txTime;
253 }
254
255 static __inline int
256 mapgsm(u_int freq, u_int flags)
257 {
258         freq *= 10;
259         if (flags & CHANNEL_QUARTER)
260                 freq += 5;
261         else if (flags & CHANNEL_HALF)
262                 freq += 10;
263         else
264                 freq += 20;
265         return (freq - 24220) / 5;
266 }
267
268 static __inline int
269 mappsb(u_int freq, u_int flags)
270 {
271         return ((freq * 10) + (((freq % 5) == 2) ? 5 : 0) - 49400) / 5;
272 }
273
274 /*
275  * Convert GHz frequency to IEEE channel number.
276  */
277 int
278 ath_hal_mhz2ieee(struct ath_hal *ah, u_int freq, u_int flags)
279 {
280         if (flags & CHANNEL_2GHZ) {     /* 2GHz band */
281                 if (freq == 2484)
282                         return 14;
283                 if (freq < 2484) {
284                         if (ath_hal_isgsmsku(ah))
285                                 return mapgsm(freq, flags);
286                         return ((int)freq - 2407) / 5;
287                 } else
288                         return 15 + ((freq - 2512) / 20);
289         } else if (flags & CHANNEL_5GHZ) {/* 5Ghz band */
290                 if (ath_hal_ispublicsafetysku(ah) &&
291                     IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
292                         return mappsb(freq, flags);
293                 } else if ((flags & CHANNEL_A) && (freq <= 5000)) {
294                         return (freq - 4000) / 5;
295                 } else {
296                         return (freq - 5000) / 5;
297                 }
298         } else {                        /* either, guess */
299                 if (freq == 2484)
300                         return 14;
301                 if (freq < 2484) {
302                         if (ath_hal_isgsmsku(ah))
303                                 return mapgsm(freq, flags);
304                         return ((int)freq - 2407) / 5;
305                 }
306                 if (freq < 5000) {
307                         if (ath_hal_ispublicsafetysku(ah) &&
308                             IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
309                                 return mappsb(freq, flags);
310                         } else if (freq > 4900) {
311                                 return (freq - 4000) / 5;
312                         } else {
313                                 return 15 + ((freq - 2512) / 20);
314                         }
315                 }
316                 return (freq - 5000) / 5;
317         }
318 }
319
320 typedef enum {
321         WIRELESS_MODE_11a   = 0,
322         WIRELESS_MODE_TURBO = 1,
323         WIRELESS_MODE_11b   = 2,
324         WIRELESS_MODE_11g   = 3,
325         WIRELESS_MODE_108g  = 4,
326
327         WIRELESS_MODE_MAX
328 } WIRELESS_MODE;
329
330 static WIRELESS_MODE
331 ath_hal_chan2wmode(struct ath_hal *ah, const HAL_CHANNEL *chan)
332 {
333         if (IS_CHAN_CCK(chan))
334                 return WIRELESS_MODE_11b;
335         if (IS_CHAN_G(chan))
336                 return WIRELESS_MODE_11g;
337         if (IS_CHAN_108G(chan))
338                 return WIRELESS_MODE_108g;
339         if (IS_CHAN_TURBO(chan))
340                 return WIRELESS_MODE_TURBO;
341         return WIRELESS_MODE_11a;
342 }
343
344 /*
345  * Convert between microseconds and core system clocks.
346  */
347                                      /* 11a Turbo  11b  11g  108g */
348 static const uint8_t CLOCK_RATE[]  = { 40,  80,   22,  44,   88  };
349
350 u_int
351 ath_hal_mac_clks(struct ath_hal *ah, u_int usecs)
352 {
353         const HAL_CHANNEL *c = (const HAL_CHANNEL *) AH_PRIVATE(ah)->ah_curchan;
354         u_int clks;
355
356         /* NB: ah_curchan may be null when called attach time */
357         if (c != AH_NULL) {
358                 clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
359                 if (IS_CHAN_HT40(c))
360                         clks <<= 1;
361                 else if (IS_CHAN_HALF_RATE(c))
362                         clks >>= 1;
363                 else if (IS_CHAN_QUARTER_RATE(c))
364                         clks >>= 2;
365         } else
366                 clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b];
367         return clks;
368 }
369
370 u_int
371 ath_hal_mac_usec(struct ath_hal *ah, u_int clks)
372 {
373         const HAL_CHANNEL *c = (const HAL_CHANNEL *) AH_PRIVATE(ah)->ah_curchan;
374         u_int usec;
375
376         /* NB: ah_curchan may be null when called attach time */
377         if (c != AH_NULL) {
378                 usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)];
379                 if (IS_CHAN_HT40(c))
380                         usec >>= 1;
381                 else if (IS_CHAN_HALF_RATE(c))
382                         usec <<= 1;
383                 else if (IS_CHAN_QUARTER_RATE(c))
384                         usec <<= 2;
385         } else
386                 usec = clks / CLOCK_RATE[WIRELESS_MODE_11b];
387         return usec;
388 }
389
390 /*
391  * Setup a h/w rate table's reverse lookup table and
392  * fill in ack durations.  This routine is called for
393  * each rate table returned through the ah_getRateTable
394  * method.  The reverse lookup tables are assumed to be
395  * initialized to zero (or at least the first entry).
396  * We use this as a key that indicates whether or not
397  * we've previously setup the reverse lookup table.
398  *
399  * XXX not reentrant, but shouldn't matter
400  */
401 void
402 ath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt)
403 {
404 #define N(a)    (sizeof(a)/sizeof(a[0]))
405         int i;
406
407         if (rt->rateCodeToIndex[0] != 0)        /* already setup */
408                 return;
409         for (i = 0; i < N(rt->rateCodeToIndex); i++)
410                 rt->rateCodeToIndex[i] = (uint8_t) -1;
411         for (i = 0; i < rt->rateCount; i++) {
412                 uint8_t code = rt->info[i].rateCode;
413                 uint8_t cix = rt->info[i].controlRate;
414
415                 HALASSERT(code < N(rt->rateCodeToIndex));
416                 rt->rateCodeToIndex[code] = i;
417                 HALASSERT((code | rt->info[i].shortPreamble) <
418                     N(rt->rateCodeToIndex));
419                 rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
420                 /*
421                  * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
422                  *     depends on whether they are marked as basic rates;
423                  *     the static tables are setup with an 11b-compatible
424                  *     2Mb/s rate which will work but is suboptimal
425                  */
426                 rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt,
427                         WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE);
428                 rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt,
429                         WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE);
430         }
431 #undef N
432 }
433
434 HAL_STATUS
435 ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
436         uint32_t capability, uint32_t *result)
437 {
438         const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
439
440         switch (type) {
441         case HAL_CAP_REG_DMN:           /* regulatory domain */
442                 *result = AH_PRIVATE(ah)->ah_currentRD;
443                 return HAL_OK;
444         case HAL_CAP_CIPHER:            /* cipher handled in hardware */
445         case HAL_CAP_TKIP_MIC:          /* handle TKIP MIC in hardware */
446                 return HAL_ENOTSUPP;
447         case HAL_CAP_TKIP_SPLIT:        /* hardware TKIP uses split keys */
448                 return HAL_ENOTSUPP;
449         case HAL_CAP_PHYCOUNTERS:       /* hardware PHY error counters */
450                 return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO;
451         case HAL_CAP_WME_TKIPMIC:   /* hardware can do TKIP MIC when WMM is turned on */
452                 return HAL_ENOTSUPP;
453         case HAL_CAP_DIVERSITY:         /* hardware supports fast diversity */
454                 return HAL_ENOTSUPP;
455         case HAL_CAP_KEYCACHE_SIZE:     /* hardware key cache size */
456                 *result =  pCap->halKeyCacheSize;
457                 return HAL_OK;
458         case HAL_CAP_NUM_TXQUEUES:      /* number of hardware tx queues */
459                 *result = pCap->halTotalQueues;
460                 return HAL_OK;
461         case HAL_CAP_VEOL:              /* hardware supports virtual EOL */
462                 return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP;
463         case HAL_CAP_PSPOLL:            /* hardware PS-Poll support works */
464                 return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK;
465         case HAL_CAP_COMPRESSION:
466                 return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP;
467         case HAL_CAP_BURST:
468                 return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP;
469         case HAL_CAP_FASTFRAME:
470                 return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP;
471         case HAL_CAP_DIAG:              /* hardware diagnostic support */
472                 *result = AH_PRIVATE(ah)->ah_diagreg;
473                 return HAL_OK;
474         case HAL_CAP_TXPOW:             /* global tx power limit  */
475                 switch (capability) {
476                 case 0:                 /* facility is supported */
477                         return HAL_OK;
478                 case 1:                 /* current limit */
479                         *result = AH_PRIVATE(ah)->ah_powerLimit;
480                         return HAL_OK;
481                 case 2:                 /* current max tx power */
482                         *result = AH_PRIVATE(ah)->ah_maxPowerLevel;
483                         return HAL_OK;
484                 case 3:                 /* scale factor */
485                         *result = AH_PRIVATE(ah)->ah_tpScale;
486                         return HAL_OK;
487                 }
488                 return HAL_ENOTSUPP;
489         case HAL_CAP_BSSIDMASK:         /* hardware supports bssid mask */
490                 return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP;
491         case HAL_CAP_MCAST_KEYSRCH:     /* multicast frame keycache search */
492                 return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP;
493         case HAL_CAP_TSF_ADJUST:        /* hardware has beacon tsf adjust */
494                 return HAL_ENOTSUPP;
495         case HAL_CAP_RFSILENT:          /* rfsilent support  */
496                 switch (capability) {
497                 case 0:                 /* facility is supported */
498                         return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP;
499                 case 1:                 /* current setting */
500                         return AH_PRIVATE(ah)->ah_rfkillEnabled ?
501                                 HAL_OK : HAL_ENOTSUPP;
502                 case 2:                 /* rfsilent config */
503                         *result = AH_PRIVATE(ah)->ah_rfsilent;
504                         return HAL_OK;
505                 }
506                 return HAL_ENOTSUPP;
507         case HAL_CAP_11D:
508 #ifdef AH_SUPPORT_11D
509                 return HAL_OK;
510 #else
511                 return HAL_ENOTSUPP;
512 #endif
513         case HAL_CAP_RXORN_FATAL:       /* HAL_INT_RXORN treated as fatal  */
514                 return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP;
515         case HAL_CAP_HT:
516                 return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP;
517         case HAL_CAP_TX_CHAINMASK:      /* mask of TX chains supported */
518                 *result = pCap->halTxChainMask;
519                 return HAL_OK;
520         case HAL_CAP_RX_CHAINMASK:      /* mask of RX chains supported */
521                 *result = pCap->halRxChainMask;
522                 return HAL_OK;
523         case HAL_CAP_RXTSTAMP_PREC:     /* rx desc tstamp precision (bits) */
524                 *result = pCap->halTstampPrecision;
525                 return HAL_OK;
526         default:
527                 return HAL_EINVAL;
528         }
529 }
530
531 HAL_BOOL
532 ath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
533         uint32_t capability, uint32_t setting, HAL_STATUS *status)
534 {
535
536         switch (type) {
537         case HAL_CAP_TXPOW:
538                 switch (capability) {
539                 case 3:
540                         if (setting <= HAL_TP_SCALE_MIN) {
541                                 AH_PRIVATE(ah)->ah_tpScale = setting;
542                                 return AH_TRUE;
543                         }
544                         break;
545                 }
546                 break;
547         case HAL_CAP_RFSILENT:          /* rfsilent support  */
548                 /*
549                  * NB: allow even if halRfSilentSupport is false
550                  *     in case the EEPROM is misprogrammed.
551                  */
552                 switch (capability) {
553                 case 1:                 /* current setting */
554                         AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0);
555                         return AH_TRUE;
556                 case 2:                 /* rfsilent config */
557                         /* XXX better done per-chip for validation? */
558                         AH_PRIVATE(ah)->ah_rfsilent = setting;
559                         return AH_TRUE;
560                 }
561                 break;
562         case HAL_CAP_REG_DMN:           /* regulatory domain */
563                 AH_PRIVATE(ah)->ah_currentRD = setting;
564                 return AH_TRUE;
565         case HAL_CAP_RXORN_FATAL:       /* HAL_INT_RXORN treated as fatal  */
566                 AH_PRIVATE(ah)->ah_rxornIsFatal = setting;
567                 return AH_TRUE;
568         default:
569                 break;
570         }
571         if (status)
572                 *status = HAL_EINVAL;
573         return AH_FALSE;
574 }
575
576 /* 
577  * Common support for getDiagState method.
578  */
579
580 static u_int
581 ath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs,
582         void *dstbuf, int space)
583 {
584         uint32_t *dp = dstbuf;
585         int i;
586
587         for (i = 0; space >= 2*sizeof(uint32_t); i++) {
588                 u_int r = regs[i].start;
589                 u_int e = regs[i].end;
590                 *dp++ = (r<<16) | e;
591                 space -= sizeof(uint32_t);
592                 do {
593                         *dp++ = OS_REG_READ(ah, r);
594                         r += sizeof(uint32_t);
595                         space -= sizeof(uint32_t);
596                 } while (r <= e && space >= sizeof(uint32_t));
597         }
598         return (char *) dp - (char *) dstbuf;
599 }
600
601 HAL_BOOL
602 ath_hal_getdiagstate(struct ath_hal *ah, int request,
603         const void *args, uint32_t argsize,
604         void **result, uint32_t *resultsize)
605 {
606         switch (request) {
607         case HAL_DIAG_REVS:
608                 *result = &AH_PRIVATE(ah)->ah_devid;
609                 *resultsize = sizeof(HAL_REVS);
610                 return AH_TRUE;
611         case HAL_DIAG_REGS:
612                 *resultsize = ath_hal_getregdump(ah, args, *result,*resultsize);
613                 return AH_TRUE;
614         case HAL_DIAG_FATALERR:
615                 *result = &AH_PRIVATE(ah)->ah_fatalState[0];
616                 *resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState);
617                 return AH_TRUE;
618         case HAL_DIAG_EEREAD:
619                 if (argsize != sizeof(uint16_t))
620                         return AH_FALSE;
621                 if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result))
622                         return AH_FALSE;
623                 *resultsize = sizeof(uint16_t);
624                 return AH_TRUE;
625 #ifdef AH_PRIVATE_DIAG
626         case HAL_DIAG_SETKEY: {
627                 const HAL_DIAG_KEYVAL *dk;
628
629                 if (argsize != sizeof(HAL_DIAG_KEYVAL))
630                         return AH_FALSE;
631                 dk = (const HAL_DIAG_KEYVAL *)args;
632                 return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix,
633                         &dk->dk_keyval, dk->dk_mac, dk->dk_xor);
634         }
635         case HAL_DIAG_RESETKEY:
636                 if (argsize != sizeof(uint16_t))
637                         return AH_FALSE;
638                 return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args);
639 #ifdef AH_SUPPORT_WRITE_EEPROM
640         case HAL_DIAG_EEWRITE: {
641                 const HAL_DIAG_EEVAL *ee;
642                 if (argsize != sizeof(HAL_DIAG_EEVAL))
643                         return AH_FALSE;
644                 ee = (const HAL_DIAG_EEVAL *)args;
645                 return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data);
646         }
647 #endif /* AH_SUPPORT_WRITE_EEPROM */
648 #endif /* AH_PRIVATE_DIAG */
649         case HAL_DIAG_11NCOMPAT:
650                 if (argsize == 0) {
651                         *resultsize = sizeof(uint32_t);
652                         *((uint32_t *)(*result)) =
653                                 AH_PRIVATE(ah)->ah_11nCompat;
654                 } else if (argsize == sizeof(uint32_t)) {
655                         AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args;
656                 } else
657                         return AH_FALSE;
658                 return AH_TRUE;
659         }
660         return AH_FALSE;
661 }
662
663 /*
664  * Set the properties of the tx queue with the parameters
665  * from qInfo.
666  */
667 HAL_BOOL
668 ath_hal_setTxQProps(struct ath_hal *ah,
669         HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo)
670 {
671         uint32_t cw;
672
673         if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
674                 HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
675                     "%s: inactive queue\n", __func__);
676                 return AH_FALSE;
677         }
678         /* XXX validate parameters */
679         qi->tqi_ver = qInfo->tqi_ver;
680         qi->tqi_subtype = qInfo->tqi_subtype;
681         qi->tqi_qflags = qInfo->tqi_qflags;
682         qi->tqi_priority = qInfo->tqi_priority;
683         if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT)
684                 qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255);
685         else
686                 qi->tqi_aifs = INIT_AIFS;
687         if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) {
688                 cw = AH_MIN(qInfo->tqi_cwmin, 1024);
689                 /* make sure that the CWmin is of the form (2^n - 1) */
690                 qi->tqi_cwmin = 1;
691                 while (qi->tqi_cwmin < cw)
692                         qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
693         } else
694                 qi->tqi_cwmin = qInfo->tqi_cwmin;
695         if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) {
696                 cw = AH_MIN(qInfo->tqi_cwmax, 1024);
697                 /* make sure that the CWmax is of the form (2^n - 1) */
698                 qi->tqi_cwmax = 1;
699                 while (qi->tqi_cwmax < cw)
700                         qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
701         } else
702                 qi->tqi_cwmax = INIT_CWMAX;
703         /* Set retry limit values */
704         if (qInfo->tqi_shretry != 0)
705                 qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15);
706         else
707                 qi->tqi_shretry = INIT_SH_RETRY;
708         if (qInfo->tqi_lgretry != 0)
709                 qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15);
710         else
711                 qi->tqi_lgretry = INIT_LG_RETRY;
712         qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod;
713         qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit;
714         qi->tqi_burstTime = qInfo->tqi_burstTime;
715         qi->tqi_readyTime = qInfo->tqi_readyTime;
716
717         switch (qInfo->tqi_subtype) {
718         case HAL_WME_UPSD:
719                 if (qi->tqi_type == HAL_TX_QUEUE_DATA)
720                         qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS;
721                 break;
722         default:
723                 break;          /* NB: silence compiler */
724         }
725         return AH_TRUE;
726 }
727
728 HAL_BOOL
729 ath_hal_getTxQProps(struct ath_hal *ah,
730         HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi)
731 {
732         if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
733                 HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
734                     "%s: inactive queue\n", __func__);
735                 return AH_FALSE;
736         }
737
738         qInfo->tqi_qflags = qi->tqi_qflags;
739         qInfo->tqi_ver = qi->tqi_ver;
740         qInfo->tqi_subtype = qi->tqi_subtype;
741         qInfo->tqi_qflags = qi->tqi_qflags;
742         qInfo->tqi_priority = qi->tqi_priority;
743         qInfo->tqi_aifs = qi->tqi_aifs;
744         qInfo->tqi_cwmin = qi->tqi_cwmin;
745         qInfo->tqi_cwmax = qi->tqi_cwmax;
746         qInfo->tqi_shretry = qi->tqi_shretry;
747         qInfo->tqi_lgretry = qi->tqi_lgretry;
748         qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
749         qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
750         qInfo->tqi_burstTime = qi->tqi_burstTime;
751         qInfo->tqi_readyTime = qi->tqi_readyTime;
752         return AH_TRUE;
753 }
754
755                                      /* 11a Turbo  11b  11g  108g */
756 static const int16_t NOISE_FLOOR[] = { -96, -93,  -98, -96,  -93 };
757
758 /*
759  * Read the current channel noise floor and return.
760  * If nf cal hasn't finished, channel noise floor should be 0
761  * and we return a nominal value based on band and frequency.
762  *
763  * NB: This is a private routine used by per-chip code to
764  *     implement the ah_getChanNoise method.
765  */
766 int16_t
767 ath_hal_getChanNoise(struct ath_hal *ah, HAL_CHANNEL *chan)
768 {
769         HAL_CHANNEL_INTERNAL *ichan;
770
771         ichan = ath_hal_checkchannel(ah, chan);
772         if (ichan == AH_NULL) {
773                 HALDEBUG(ah, HAL_DEBUG_NFCAL,
774                     "%s: invalid channel %u/0x%x; no mapping\n",
775                     __func__, chan->channel, chan->channelFlags);
776                 return 0;
777         }
778         if (ichan->rawNoiseFloor == 0) {
779                 WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan);
780
781                 HALASSERT(mode < WIRELESS_MODE_MAX);
782                 return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan);
783         } else
784                 return ichan->rawNoiseFloor + ichan->noiseFloorAdjust;
785 }
786
787 /*
788  * Process all valid raw noise floors into the dBm noise floor values.
789  * Though our device has no reference for a dBm noise floor, we perform
790  * a relative minimization of NF's based on the lowest NF found across a
791  * channel scan.
792  */
793 void
794 ath_hal_process_noisefloor(struct ath_hal *ah)
795 {
796         HAL_CHANNEL_INTERNAL *c;
797         int16_t correct2, correct5;
798         int16_t lowest2, lowest5;
799         int i;
800
801         /* 
802          * Find the lowest 2GHz and 5GHz noise floor values after adjusting
803          * for statistically recorded NF/channel deviation.
804          */
805         correct2 = lowest2 = 0;
806         correct5 = lowest5 = 0;
807         for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
808                 WIRELESS_MODE mode;
809                 int16_t nf;
810
811                 c = &AH_PRIVATE(ah)->ah_channels[i];
812                 if (c->rawNoiseFloor >= 0)
813                         continue;
814                 mode = ath_hal_chan2wmode(ah, (HAL_CHANNEL *) c);
815                 HALASSERT(mode < WIRELESS_MODE_MAX);
816                 nf = c->rawNoiseFloor + NOISE_FLOOR[mode] +
817                         ath_hal_getNfAdjust(ah, c);
818                 if (IS_CHAN_5GHZ(c)) {
819                         if (nf < lowest5) { 
820                                 lowest5 = nf;
821                                 correct5 = NOISE_FLOOR[mode] -
822                                     (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
823                         }
824                 } else {
825                         if (nf < lowest2) { 
826                                 lowest2 = nf;
827                                 correct2 = NOISE_FLOOR[mode] -
828                                     (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c));
829                         }
830                 }
831         }
832
833         /* Correct the channels to reach the expected NF value */
834         for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) {
835                 c = &AH_PRIVATE(ah)->ah_channels[i];
836                 if (c->rawNoiseFloor >= 0)
837                         continue;
838                 /* Apply correction factor */
839                 c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) +
840                         (IS_CHAN_5GHZ(c) ? correct5 : correct2);
841                 HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u/0x%x raw nf %d adjust %d\n",
842                     c->channel, c->channelFlags, c->rawNoiseFloor,
843                     c->noiseFloorAdjust);
844         }
845 }
846
847 /*
848  * INI support routines.
849  */
850
851 int
852 ath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
853         int col, int regWr)
854 {
855         int r;
856
857         for (r = 0; r < ia->rows; r++) {
858                 OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0),
859                     HAL_INI_VAL(ia, r, col));
860                 DMA_YIELD(regWr);
861         }
862         return regWr;
863 }
864
865 void
866 ath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col)
867 {
868         int r;
869
870         for (r = 0; r < ia->rows; r++)
871                 data[r] = HAL_INI_VAL(ia, r, col);
872 }
873
874 int
875 ath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia,
876         const uint32_t data[], int regWr)
877 {
878         int r;
879
880         for (r = 0; r < ia->rows; r++) {
881                 OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]);
882                 DMA_YIELD(regWr);
883         }
884         return regWr;
885 }