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