4f374c4beea25a493209dffc917d7a62daba56a5
[dragonfly.git] / sys / dev / netif / ath / ath_hal / ah_regdomain.c
1 /*
2  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3  * Copyright (c) 2005-2006 Atheros Communications, Inc.
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * $FreeBSD$
19  */
20 #include "opt_ah.h"
21
22 #include "ah.h"
23
24 #include <net80211/_ieee80211.h>
25 #include <net80211/ieee80211_regdomain.h>
26
27 #include "ah_internal.h"
28 #include "ah_eeprom.h"
29 #include "ah_devid.h"
30
31 #include "ah_regdomain.h"
32
33 /*
34  * XXX this code needs a audit+review
35  */
36
37 /* used throughout this file... */
38 #define N(a)    (sizeof (a) / sizeof (a[0]))
39
40 #define HAL_MODE_11A_TURBO      HAL_MODE_108A
41 #define HAL_MODE_11G_TURBO      HAL_MODE_108G
42
43 /*
44  * Mask to check whether a domain is a multidomain or a single domain
45  */
46 #define MULTI_DOMAIN_MASK 0xFF00
47
48 /*
49  * Enumerated Regulatory Domain Information 8 bit values indicate that
50  * the regdomain is really a pair of unitary regdomains.  12 bit values
51  * are the real unitary regdomains and are the only ones which have the
52  * frequency bitmasks and flags set.
53  */
54 #include "ah_regdomain/ah_rd_regenum.h"
55
56 #define WORLD_SKU_MASK          0x00F0
57 #define WORLD_SKU_PREFIX        0x0060
58
59 /*
60  * THE following table is the mapping of regdomain pairs specified by
61  * an 8 bit regdomain value to the individual unitary reg domains
62  */
63 #include "ah_regdomain/ah_rd_regmap.h"
64
65 /* 
66  * The following tables are the master list for all different freqeuncy
67  * bands with the complete matrix of all possible flags and settings
68  * for each band if it is used in ANY reg domain.
69  */
70
71 #define COUNTRY_ERD_FLAG        0x8000
72 #define WORLDWIDE_ROAMING_FLAG  0x4000
73
74 /*
75  * This table maps country ISO codes from net80211 into regulatory
76  * domains which the ath regulatory domain code understands.
77  */
78 #include "ah_regdomain/ah_rd_ctry.h"
79
80 /*
81  * The frequency band collections are a set of frequency ranges
82  * with shared properties - max tx power, max antenna gain, channel width,
83  * channel spacing, DFS requirements and passive scanning requirements.
84  *
85  * These are represented as entries in a frequency band bitmask.
86  * Each regulatory domain entry in ah_regdomain_domains.h uses one
87  * or more frequency band entries for each of the channel modes
88  * supported (11bg, 11a, half, quarter, turbo, etc.)
89  *
90  */
91 #include "ah_regdomain/ah_rd_freqbands.h"
92
93 /*
94  * This is the main regulatory database. It defines the supported
95  * set of features and requirements for each of the defined regulatory
96  * zones. It uses combinations of frequency ranges - represented in
97  * a bitmask - to determine the requirements and limitations needed.
98  */
99 #include "ah_regdomain/ah_rd_domains.h"
100
101 static const struct cmode modes[] = {
102         { HAL_MODE_TURBO,       IEEE80211_CHAN_ST },
103         { HAL_MODE_11A,         IEEE80211_CHAN_A },
104         { HAL_MODE_11B,         IEEE80211_CHAN_B },
105         { HAL_MODE_11G,         IEEE80211_CHAN_G },
106         { HAL_MODE_11G_TURBO,   IEEE80211_CHAN_108G },
107         { HAL_MODE_11A_TURBO,   IEEE80211_CHAN_108A },
108         { HAL_MODE_11A_QUARTER_RATE,
109           IEEE80211_CHAN_A | IEEE80211_CHAN_QUARTER },
110         { HAL_MODE_11A_HALF_RATE,
111           IEEE80211_CHAN_A | IEEE80211_CHAN_HALF },
112         { HAL_MODE_11G_QUARTER_RATE,
113           IEEE80211_CHAN_G | IEEE80211_CHAN_QUARTER },
114         { HAL_MODE_11G_HALF_RATE,
115           IEEE80211_CHAN_G | IEEE80211_CHAN_HALF },
116         { HAL_MODE_11NG_HT20,   IEEE80211_CHAN_G | IEEE80211_CHAN_HT20 },
117         { HAL_MODE_11NG_HT40PLUS,
118           IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U },
119         { HAL_MODE_11NG_HT40MINUS,
120           IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D },
121         { HAL_MODE_11NA_HT20,   IEEE80211_CHAN_A | IEEE80211_CHAN_HT20 },
122         { HAL_MODE_11NA_HT40PLUS,
123           IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U },
124         { HAL_MODE_11NA_HT40MINUS,
125           IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D },
126 };
127
128 static void ath_hal_update_dfsdomain(struct ath_hal *ah);
129
130 static OS_INLINE uint16_t
131 getEepromRD(struct ath_hal *ah)
132 {
133         return AH_PRIVATE(ah)->ah_currentRD &~ WORLDWIDE_ROAMING_FLAG;
134 }
135
136 /*
137  * Test to see if the bitmask array is all zeros
138  */
139 static HAL_BOOL
140 isChanBitMaskZero(const uint64_t *bitmask)
141 {
142 #if BMLEN > 2
143 #error  "add more cases"
144 #endif
145 #if BMLEN > 1
146         if (bitmask[1] != 0)
147                 return AH_FALSE;
148 #endif
149         return (bitmask[0] == 0);
150 }
151
152 /*
153  * Return whether or not the regulatory domain/country in EEPROM
154  * is acceptable.
155  */
156 static HAL_BOOL
157 isEepromValid(struct ath_hal *ah)
158 {
159         uint16_t rd = getEepromRD(ah);
160         int i;
161
162         if (rd & COUNTRY_ERD_FLAG) {
163                 uint16_t cc = rd &~ COUNTRY_ERD_FLAG;
164                 for (i = 0; i < N(allCountries); i++)
165                         if (allCountries[i].countryCode == cc)
166                                 return AH_TRUE;
167         } else {
168                 for (i = 0; i < N(regDomainPairs); i++)
169                         if (regDomainPairs[i].regDmnEnum == rd)
170                                 return AH_TRUE;
171         }
172
173         if (rd == FCC_UBNT) {
174                 return AH_TRUE;
175         }
176
177         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
178             "%s: invalid regulatory domain/country code 0x%x\n", __func__, rd);
179         return AH_FALSE;
180 }
181
182 /*
183  * Find the pointer to the country element in the country table
184  * corresponding to the country code
185  */
186 static COUNTRY_CODE_TO_ENUM_RD*
187 findCountry(HAL_CTRY_CODE countryCode)
188 {
189         int i;
190
191         for (i = 0; i < N(allCountries); i++) {
192                 if (allCountries[i].countryCode == countryCode)
193                         return &allCountries[i];
194         }
195         return AH_NULL;
196 }
197
198 static REG_DOMAIN *
199 findRegDmn(int regDmn)
200 {
201         int i;
202
203         for (i = 0; i < N(regDomains); i++) {
204                 if (regDomains[i].regDmnEnum == regDmn)
205                         return &regDomains[i];
206         }
207         return AH_NULL;
208 }
209
210 static REG_DMN_PAIR_MAPPING *
211 findRegDmnPair(int regDmnPair)
212 {
213         int i;
214
215         if (regDmnPair != NO_ENUMRD) {
216                 for (i = 0; i < N(regDomainPairs); i++) {
217                         if (regDomainPairs[i].regDmnEnum == regDmnPair)
218                                 return &regDomainPairs[i];
219                 }
220         }
221         return AH_NULL;
222 }
223
224 /*
225  * Calculate a default country based on the EEPROM setting.
226  */
227 static HAL_CTRY_CODE
228 getDefaultCountry(struct ath_hal *ah)
229 {
230         REG_DMN_PAIR_MAPPING *regpair;
231         uint16_t rd;
232
233         rd = getEepromRD(ah);
234         if (rd & COUNTRY_ERD_FLAG) {
235                 COUNTRY_CODE_TO_ENUM_RD *country;
236                 uint16_t cc = rd & ~COUNTRY_ERD_FLAG;
237                 country = findCountry(cc);
238                 if (country != AH_NULL)
239                         return cc;
240         }
241         /*
242          * Check reg domains that have only one country
243          */
244         regpair = findRegDmnPair(rd);
245         return (regpair != AH_NULL) ? regpair->singleCC : CTRY_DEFAULT;
246 }
247
248 static HAL_BOOL
249 IS_BIT_SET(int bit, const uint64_t bitmask[])
250 {
251         int byteOffset, bitnum;
252         uint64_t val;
253
254         byteOffset = bit/64;
255         bitnum = bit - byteOffset*64;
256         val = ((uint64_t) 1) << bitnum;
257         return (bitmask[byteOffset] & val) != 0;
258 }
259
260 static HAL_STATUS
261 getregstate(struct ath_hal *ah, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
262     COUNTRY_CODE_TO_ENUM_RD **pcountry,
263     REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz)
264 {
265         COUNTRY_CODE_TO_ENUM_RD *country;
266         REG_DOMAIN *rd5GHz, *rd2GHz;
267
268         if (cc == CTRY_DEFAULT && regDmn == SKU_NONE) {
269                 /*
270                  * Validate the EEPROM setting and setup defaults
271                  */
272                 if (!isEepromValid(ah)) {
273                         /*
274                          * Don't return any channels if the EEPROM has an
275                          * invalid regulatory domain/country code setting.
276                          */
277                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
278                             "%s: invalid EEPROM contents\n",__func__);
279                         return HAL_EEBADREG;
280                 }
281
282                 cc = getDefaultCountry(ah);
283                 country = findCountry(cc);
284                 if (country == AH_NULL) {
285                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
286                             "NULL Country!, cc %d\n", cc);
287                         return HAL_EEBADCC;
288                 }
289                 regDmn = country->regDmnEnum;
290                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: EEPROM cc %u rd 0x%x\n",
291                     __func__, cc, regDmn);
292
293                 if (country->countryCode == CTRY_DEFAULT) {
294                         /*
295                          * Check EEPROM; SKU may be for a country, single
296                          * domain, or multiple domains (WWR).
297                          */
298                         uint16_t rdnum = getEepromRD(ah);
299                         if ((rdnum & COUNTRY_ERD_FLAG) == 0 &&
300                             (findRegDmn(rdnum) != AH_NULL ||
301                              findRegDmnPair(rdnum) != AH_NULL)) {
302                                 regDmn = rdnum;
303                                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
304                                     "%s: EEPROM rd 0x%x\n", __func__, rdnum);
305                         }
306                 }
307         } else {
308                 country = findCountry(cc);
309                 if (country == AH_NULL) {
310                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
311                             "unknown country, cc %d\n", cc);
312                         return HAL_EINVAL;
313                 }
314                 if (regDmn == SKU_NONE)
315                         regDmn = country->regDmnEnum;
316                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u rd 0x%x\n",
317                     __func__, cc, regDmn);
318         }
319
320         /*
321          * Setup per-band state.
322          */
323         if ((regDmn & MULTI_DOMAIN_MASK) == 0) {
324                 REG_DMN_PAIR_MAPPING *regpair = findRegDmnPair(regDmn);
325                 if (regpair == AH_NULL) {
326                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
327                             "%s: no reg domain pair %u for country %u\n",
328                             __func__, regDmn, country->countryCode);
329                         return HAL_EINVAL;
330                 }
331                 rd5GHz = findRegDmn(regpair->regDmn5GHz);
332                 if (rd5GHz == AH_NULL) {
333                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
334                             "%s: no 5GHz reg domain %u for country %u\n",
335                             __func__, regpair->regDmn5GHz, country->countryCode);
336                         return HAL_EINVAL;
337                 }
338                 rd2GHz = findRegDmn(regpair->regDmn2GHz);
339                 if (rd2GHz == AH_NULL) {
340                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
341                             "%s: no 2GHz reg domain %u for country %u\n",
342                             __func__, regpair->regDmn2GHz, country->countryCode);
343                         return HAL_EINVAL;
344                 }
345         } else {
346                 rd5GHz = rd2GHz = findRegDmn(regDmn);
347                 if (rd2GHz == AH_NULL) {
348                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
349                             "%s: no unitary reg domain %u for country %u\n",
350                             __func__, regDmn, country->countryCode);
351                         return HAL_EINVAL;
352                 }
353         }
354         if (pcountry != AH_NULL)
355                 *pcountry = country;
356         *prd2GHz = rd2GHz;
357         *prd5GHz = rd5GHz;
358         return HAL_OK;
359 }
360
361 /*
362  * Construct the channel list for the specified regulatory config.
363  */
364 static HAL_STATUS
365 getchannels(struct ath_hal *ah,
366     struct ieee80211_channel chans[], u_int maxchans, int *nchans,
367     u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
368     HAL_BOOL enableExtendedChannels,
369     COUNTRY_CODE_TO_ENUM_RD **pcountry,
370     REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz)
371 {
372 #define CHANNEL_HALF_BW         10
373 #define CHANNEL_QUARTER_BW      5
374 #define HAL_MODE_11A_ALL \
375         (HAL_MODE_11A | HAL_MODE_11A_TURBO | HAL_MODE_TURBO | \
376          HAL_MODE_11A_QUARTER_RATE | HAL_MODE_11A_HALF_RATE)
377         REG_DOMAIN *rd5GHz, *rd2GHz;
378         u_int modesAvail;
379         const struct cmode *cm;
380         struct ieee80211_channel *ic;
381         int next, b;
382         HAL_STATUS status;
383
384         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u regDmn 0x%x mode 0x%x%s\n",
385             __func__, cc, regDmn, modeSelect, 
386             enableExtendedChannels ? " ecm" : "");
387
388         status = getregstate(ah, cc, regDmn, pcountry, &rd2GHz, &rd5GHz);
389         if (status != HAL_OK)
390                 return status;
391
392         /* get modes that HW is capable of */
393         modesAvail = ath_hal_getWirelessModes(ah);
394         /* optimize work below if no 11a channels */
395         if (isChanBitMaskZero(rd5GHz->chan11a) &&
396             (modesAvail & HAL_MODE_11A_ALL)) {
397                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
398                     "%s: disallow all 11a\n", __func__);
399                 modesAvail &= ~HAL_MODE_11A_ALL;
400         }
401
402         next = 0;
403         ic = &chans[0];
404         for (cm = modes; cm < &modes[N(modes)]; cm++) {
405                 uint16_t c, c_hi, c_lo;
406                 uint64_t *channelBM = AH_NULL;
407                 REG_DMN_FREQ_BAND *fband = AH_NULL,*freqs;
408                 int low_adj, hi_adj, channelSep, lastc;
409                 uint32_t rdflags;
410                 uint64_t dfsMask;
411                 uint64_t pscan;
412
413                 if ((cm->mode & modeSelect) == 0) {
414                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
415                             "%s: skip mode 0x%x flags 0x%x\n",
416                             __func__, cm->mode, cm->flags);
417                         continue;
418                 }
419                 if ((cm->mode & modesAvail) == 0) {
420                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
421                             "%s: !avail mode 0x%x (0x%x) flags 0x%x\n",
422                             __func__, modesAvail, cm->mode, cm->flags);
423                         continue;
424                 }
425                 if (!ath_hal_getChannelEdges(ah, cm->flags, &c_lo, &c_hi)) {
426                         /* channel not supported by hardware, skip it */
427                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
428                             "%s: channels 0x%x not supported by hardware\n",
429                             __func__,cm->flags);
430                         continue;
431                 }
432                 switch (cm->mode) {
433                 case HAL_MODE_TURBO:
434                 case HAL_MODE_11A_TURBO:
435                         rdflags = rd5GHz->flags;
436                         dfsMask = rd5GHz->dfsMask;
437                         pscan = rd5GHz->pscan;
438                         if (cm->mode == HAL_MODE_TURBO)
439                                 channelBM = rd5GHz->chan11a_turbo;
440                         else
441                                 channelBM = rd5GHz->chan11a_dyn_turbo;
442                         freqs = &regDmn5GhzTurboFreq[0];
443                         break;
444                 case HAL_MODE_11G_TURBO:
445                         rdflags = rd2GHz->flags;
446                         dfsMask = rd2GHz->dfsMask;
447                         pscan = rd2GHz->pscan;
448                         channelBM = rd2GHz->chan11g_turbo;
449                         freqs = &regDmn2Ghz11gTurboFreq[0];
450                         break;
451                 case HAL_MODE_11A:
452                 case HAL_MODE_11A_HALF_RATE:
453                 case HAL_MODE_11A_QUARTER_RATE:
454                 case HAL_MODE_11NA_HT20:
455                 case HAL_MODE_11NA_HT40PLUS:
456                 case HAL_MODE_11NA_HT40MINUS:
457                         rdflags = rd5GHz->flags;
458                         dfsMask = rd5GHz->dfsMask;
459                         pscan = rd5GHz->pscan;
460                         if (cm->mode == HAL_MODE_11A_HALF_RATE)
461                                 channelBM = rd5GHz->chan11a_half;
462                         else if (cm->mode == HAL_MODE_11A_QUARTER_RATE)
463                                 channelBM = rd5GHz->chan11a_quarter;
464                         else
465                                 channelBM = rd5GHz->chan11a;
466                         freqs = &regDmn5GhzFreq[0];
467                         break;
468                 case HAL_MODE_11B:
469                 case HAL_MODE_11G:
470                 case HAL_MODE_11G_HALF_RATE:
471                 case HAL_MODE_11G_QUARTER_RATE:
472                 case HAL_MODE_11NG_HT20:
473                 case HAL_MODE_11NG_HT40PLUS:
474                 case HAL_MODE_11NG_HT40MINUS:
475                         rdflags = rd2GHz->flags;
476                         dfsMask = rd2GHz->dfsMask;
477                         pscan = rd2GHz->pscan;
478                         if (cm->mode == HAL_MODE_11G_HALF_RATE)
479                                 channelBM = rd2GHz->chan11g_half;
480                         else if (cm->mode == HAL_MODE_11G_QUARTER_RATE)
481                                 channelBM = rd2GHz->chan11g_quarter;
482                         else if (cm->mode == HAL_MODE_11B)
483                                 channelBM = rd2GHz->chan11b;
484                         else
485                                 channelBM = rd2GHz->chan11g;
486                         if (cm->mode == HAL_MODE_11B)
487                                 freqs = &regDmn2GhzFreq[0];
488                         else
489                                 freqs = &regDmn2Ghz11gFreq[0];
490                         break;
491                 default:
492                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
493                             "%s: Unknown HAL mode 0x%x\n", __func__, cm->mode);
494                         continue;
495                 }
496                 if (isChanBitMaskZero(channelBM))
497                         continue;
498                 /*
499                  * Setup special handling for HT40 channels; e.g.
500                  * 5G HT40 channels require 40Mhz channel separation.
501                  */
502                 hi_adj = (cm->mode == HAL_MODE_11NA_HT40PLUS ||
503                     cm->mode == HAL_MODE_11NG_HT40PLUS) ? -20 : 0;
504                 low_adj = (cm->mode == HAL_MODE_11NA_HT40MINUS || 
505                     cm->mode == HAL_MODE_11NG_HT40MINUS) ? 20 : 0;
506                 channelSep = (cm->mode == HAL_MODE_11NA_HT40PLUS ||
507                     cm->mode == HAL_MODE_11NA_HT40MINUS) ? 40 : 0;
508
509                 for (b = 0; b < 64*BMLEN; b++) {
510                         if (!IS_BIT_SET(b, channelBM))
511                                 continue;
512                         fband = &freqs[b];
513                         lastc = 0;
514
515                         for (c = fband->lowChannel + low_adj;
516                              c <= fband->highChannel + hi_adj;
517                              c += fband->channelSep) {
518                                 if (!(c_lo <= c && c <= c_hi)) {
519                                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
520                                             "%s: c %u out of range [%u..%u]\n",
521                                             __func__, c, c_lo, c_hi);
522                                         continue;
523                                 }
524                                 if (next >= maxchans){
525                                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
526                                             "%s: too many channels for channel table\n",
527                                             __func__);
528                                         goto done;
529                                 }
530                                 if ((fband->usePassScan & IS_ECM_CHAN) &&
531                                     !enableExtendedChannels) {
532                                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
533                                             "skip ecm channel\n");
534                                         continue;
535                                 }
536 #if 0
537                                 if ((fband->useDfs & dfsMask) && 
538                                     (cm->flags & IEEE80211_CHAN_HT40)) {
539                                         /* NB: DFS and HT40 don't mix */
540                                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
541                                             "skip HT40 chan, DFS required\n");
542                                         continue;
543                                 }
544 #endif
545                                 /*
546                                  * Make sure that channel separation
547                                  * meets the requirement.
548                                  */
549                                 if (lastc && channelSep &&
550                                     (c-lastc) < channelSep)
551                                         continue;
552                                 lastc = c;
553
554                                 OS_MEMZERO(ic, sizeof(*ic));
555                                 ic->ic_freq = c;
556                                 ic->ic_flags = cm->flags;
557                                 ic->ic_maxregpower = fband->powerDfs;
558                                 ath_hal_getpowerlimits(ah, ic);
559                                 ic->ic_maxantgain = fband->antennaMax;
560                                 if (fband->usePassScan & pscan)
561                                         ic->ic_flags |= IEEE80211_CHAN_PASSIVE;
562                                 if (fband->useDfs & dfsMask)
563                                         ic->ic_flags |= IEEE80211_CHAN_DFS;
564                                 if (IEEE80211_IS_CHAN_5GHZ(ic) &&
565                                     (rdflags & DISALLOW_ADHOC_11A))
566                                         ic->ic_flags |= IEEE80211_CHAN_NOADHOC;
567                                 if (IEEE80211_IS_CHAN_TURBO(ic) &&
568                                     (rdflags & DISALLOW_ADHOC_11A_TURB))
569                                         ic->ic_flags |= IEEE80211_CHAN_NOADHOC;
570                                 if (rdflags & NO_HOSTAP)
571                                         ic->ic_flags |= IEEE80211_CHAN_NOHOSTAP;
572                                 if (rdflags & LIMIT_FRAME_4MS)
573                                         ic->ic_flags |= IEEE80211_CHAN_4MSXMIT;
574                                 if (rdflags & NEED_NFC)
575                                         ic->ic_flags |= CHANNEL_NFCREQUIRED;
576
577                                 ic++, next++;
578                         }
579                 }
580         }
581 done:
582         *nchans = next;
583         /* NB: pcountry set above by getregstate */
584         if (prd2GHz != AH_NULL)
585                 *prd2GHz = rd2GHz;
586         if (prd5GHz != AH_NULL)
587                 *prd5GHz = rd5GHz;
588         return HAL_OK;
589 #undef HAL_MODE_11A_ALL
590 #undef CHANNEL_HALF_BW
591 #undef CHANNEL_QUARTER_BW
592 }
593
594 /*
595  * Retrieve a channel list without affecting runtime state.
596  */
597 HAL_STATUS
598 ath_hal_getchannels(struct ath_hal *ah,
599     struct ieee80211_channel chans[], u_int maxchans, int *nchans,
600     u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
601     HAL_BOOL enableExtendedChannels)
602 {
603         return getchannels(ah, chans, maxchans, nchans, modeSelect,
604             cc, regDmn, enableExtendedChannels, AH_NULL, AH_NULL, AH_NULL);
605 }
606
607 /*
608  * Handle frequency mapping from 900Mhz range to 2.4GHz range
609  * for GSM radios.  This is done when we need the h/w frequency
610  * and the channel is marked IEEE80211_CHAN_GSM.
611  */
612 static int
613 ath_hal_mapgsm(int sku, int freq)
614 {
615         if (sku == SKU_XR9)
616                 return 1520 + freq;
617         if (sku == SKU_GZ901)
618                 return 1544 + freq;
619         if (sku == SKU_SR9)
620                 return 3344 - freq;
621         if (sku == SKU_XC900M)
622                 return 1517 + freq;
623         HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
624             "%s: cannot map freq %u unknown gsm sku %u\n",
625             __func__, freq, sku);
626         return freq;
627 }
628
629 /*
630  * Setup the internal/private channel state given a table of
631  * net80211 channels.  We collapse entries for the same frequency
632  * and record the frequency for doing noise floor processing
633  * where we don't have net80211 channel context.
634  */
635 static HAL_BOOL
636 assignPrivateChannels(struct ath_hal *ah,
637         struct ieee80211_channel chans[], int nchans, int sku)
638 {
639         HAL_CHANNEL_INTERNAL *ic;
640         int i, j, next, freq;
641
642         next = 0;
643         for (i = 0; i < nchans; i++) {
644                 struct ieee80211_channel *c = &chans[i];
645                 for (j = i-1; j >= 0; j--)
646                         if (chans[j].ic_freq == c->ic_freq) {
647                                 c->ic_devdata = chans[j].ic_devdata;
648                                 break;
649                         }
650                 if (j < 0) {
651                         /* new entry, assign a private channel entry */
652                         if (next >= N(AH_PRIVATE(ah)->ah_channels)) {
653                                 HALDEBUG(ah, HAL_DEBUG_ANY,
654                                     "%s: too many channels, max %zu\n",
655                                     __func__, N(AH_PRIVATE(ah)->ah_channels));
656                                 return AH_FALSE;
657                         }
658                         /*
659                          * Handle frequency mapping for 900MHz devices.
660                          * The hardware uses 2.4GHz frequencies that are
661                          * down-converted.  The 802.11 layer uses the
662                          * true frequencies.
663                          */
664                         freq = IEEE80211_IS_CHAN_GSM(c) ?
665                             ath_hal_mapgsm(sku, c->ic_freq) : c->ic_freq;
666
667                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
668                             "%s: private[%3u] %u/0x%x -> channel %u\n",
669                             __func__, next, c->ic_freq, c->ic_flags, freq);
670
671                         ic = &AH_PRIVATE(ah)->ah_channels[next];
672                         /*
673                          * NB: This clears privFlags which means ancillary
674                          *     code like ANI and IQ calibration will be
675                          *     restarted and re-setup any per-channel state.
676                          */
677                         OS_MEMZERO(ic, sizeof(*ic));
678                         ic->channel = freq;
679                         c->ic_devdata = next;
680                         next++;
681                 }
682         }
683         AH_PRIVATE(ah)->ah_nchan = next;
684         HALDEBUG(ah, HAL_DEBUG_ANY, "%s: %u public, %u private channels\n",
685             __func__, nchans, next);
686         return AH_TRUE;
687 }
688
689 /*
690  * Setup the channel list based on the information in the EEPROM.
691  */
692 HAL_STATUS
693 ath_hal_init_channels(struct ath_hal *ah,
694     struct ieee80211_channel chans[], u_int maxchans, int *nchans,
695     u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
696     HAL_BOOL enableExtendedChannels)
697 {
698         COUNTRY_CODE_TO_ENUM_RD *country;
699         REG_DOMAIN *rd5GHz, *rd2GHz;
700         HAL_STATUS status;
701
702         status = getchannels(ah, chans, maxchans, nchans, modeSelect,
703             cc, regDmn, enableExtendedChannels, &country, &rd2GHz, &rd5GHz);
704         if (status == HAL_OK &&
705             assignPrivateChannels(ah, chans, *nchans, AH_PRIVATE(ah)->ah_currentRD)) {
706                 AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz;
707                 AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz;
708
709                 ah->ah_countryCode = country->countryCode;
710                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n",
711                     __func__, ah->ah_countryCode);
712
713                 /* Update current DFS domain */
714                 ath_hal_update_dfsdomain(ah);
715         } else
716                 status = HAL_EINVAL;
717
718         return status;
719 }
720
721 /*
722  * Set the channel list.
723  */
724 HAL_STATUS
725 ath_hal_set_channels(struct ath_hal *ah,
726     struct ieee80211_channel chans[], int nchans,
727     HAL_CTRY_CODE cc, HAL_REG_DOMAIN rd)
728 {
729         COUNTRY_CODE_TO_ENUM_RD *country;
730         REG_DOMAIN *rd5GHz, *rd2GHz;
731         HAL_STATUS status;
732
733         switch (rd) {
734         case SKU_SR9:
735         case SKU_XR9:
736         case SKU_GZ901:
737         case SKU_XC900M:
738                 /*
739                  * Map 900MHz sku's.  The frequencies will be mapped
740                  * according to the sku to compensate for the down-converter.
741                  * We use the FCC for these sku's as the mapped channel
742                  * list is known compatible (will need to change if/when
743                  * vendors do different mapping in different locales).
744                  */
745                 status = getregstate(ah, CTRY_DEFAULT, SKU_FCC,
746                     &country, &rd2GHz, &rd5GHz);
747                 break;
748         default:
749                 status = getregstate(ah, cc, rd,
750                     &country, &rd2GHz, &rd5GHz);
751                 rd = AH_PRIVATE(ah)->ah_currentRD;
752                 break;
753         }
754         if (status == HAL_OK && assignPrivateChannels(ah, chans, nchans, rd)) {
755                 AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz;
756                 AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz;
757
758                 ah->ah_countryCode = country->countryCode;
759                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n",
760                     __func__, ah->ah_countryCode);
761         } else
762                 status = HAL_EINVAL;
763
764         if (status == HAL_OK) {
765                 /* Update current DFS domain */
766                 (void) ath_hal_update_dfsdomain(ah);
767         }
768         return status;
769 }
770
771 #ifdef AH_DEBUG
772 /*
773  * Return the internal channel corresponding to a public channel.
774  * NB: normally this routine is inline'd (see ah_internal.h)
775  */
776 HAL_CHANNEL_INTERNAL *
777 ath_hal_checkchannel(struct ath_hal *ah, const struct ieee80211_channel *c)
778 {
779         HAL_CHANNEL_INTERNAL *cc = &AH_PRIVATE(ah)->ah_channels[c->ic_devdata];
780
781         if (c->ic_devdata < AH_PRIVATE(ah)->ah_nchan &&
782             (c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c)))
783                 return cc;
784         if (c->ic_devdata >= AH_PRIVATE(ah)->ah_nchan) {
785                 HALDEBUG(ah, HAL_DEBUG_ANY,
786                     "%s: bad mapping, devdata %u nchans %u\n",
787                    __func__, c->ic_devdata, AH_PRIVATE(ah)->ah_nchan);
788                 HALASSERT(c->ic_devdata < AH_PRIVATE(ah)->ah_nchan);
789         } else {
790                 HALDEBUG(ah, HAL_DEBUG_ANY,
791                     "%s: no match for %u/0x%x devdata %u channel %u\n",
792                    __func__, c->ic_freq, c->ic_flags, c->ic_devdata,
793                    cc->channel);
794                 HALASSERT(c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c));
795         }
796         return AH_NULL;
797 }
798 #endif /* AH_DEBUG */
799
800 #define isWwrSKU(_ah) \
801         ((getEepromRD((_ah)) & WORLD_SKU_MASK) == WORLD_SKU_PREFIX || \
802           getEepromRD(_ah) == WORLD)
803
804 /*
805  * Return the test group for the specific channel based on
806  * the current regulatory setup.
807  */
808 u_int
809 ath_hal_getctl(struct ath_hal *ah, const struct ieee80211_channel *c)
810 {
811         u_int ctl;
812
813         if (AH_PRIVATE(ah)->ah_rd2GHz == AH_PRIVATE(ah)->ah_rd5GHz ||
814             (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)))
815                 ctl = SD_NO_CTL;
816         else if (IEEE80211_IS_CHAN_2GHZ(c))
817                 ctl = AH_PRIVATE(ah)->ah_rd2GHz->conformanceTestLimit;
818         else
819                 ctl = AH_PRIVATE(ah)->ah_rd5GHz->conformanceTestLimit;
820         if (IEEE80211_IS_CHAN_B(c))
821                 return ctl | CTL_11B;
822         if (IEEE80211_IS_CHAN_G(c))
823                 return ctl | CTL_11G;
824         if (IEEE80211_IS_CHAN_108G(c))
825                 return ctl | CTL_108G;
826         if (IEEE80211_IS_CHAN_TURBO(c))
827                 return ctl | CTL_TURBO;
828         if (IEEE80211_IS_CHAN_A(c))
829                 return ctl | CTL_11A;
830         return ctl;
831 }
832
833
834 /*
835  * Update the current dfsDomain setting based on the given
836  * country code.
837  *
838  * Since FreeBSD/net80211 allows the channel set to change
839  * after the card has been setup (via ath_hal_init_channels())
840  * this function method is needed to update ah_dfsDomain.
841  */
842 void
843 ath_hal_update_dfsdomain(struct ath_hal *ah)
844 {
845         const REG_DOMAIN *rd5GHz = AH_PRIVATE(ah)->ah_rd5GHz;
846         HAL_DFS_DOMAIN dfsDomain = HAL_DFS_UNINIT_DOMAIN;
847
848         if (rd5GHz->dfsMask & DFS_FCC3)
849                 dfsDomain = HAL_DFS_FCC_DOMAIN;
850         if (rd5GHz->dfsMask & DFS_ETSI)
851                 dfsDomain = HAL_DFS_ETSI_DOMAIN;
852         if (rd5GHz->dfsMask & DFS_MKK4)
853                 dfsDomain = HAL_DFS_MKK4_DOMAIN;
854         AH_PRIVATE(ah)->ah_dfsDomain = dfsDomain;
855         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s ah_dfsDomain: %d\n",
856             __func__, AH_PRIVATE(ah)->ah_dfsDomain);
857 }
858
859
860 /*
861  * Return the max allowed antenna gain and apply any regulatory
862  * domain specific changes.
863  *
864  * NOTE: a negative reduction is possible in RD's that only
865  * measure radiated power (e.g., ETSI) which would increase
866  * that actual conducted output power (though never beyond
867  * the calibrated target power).
868  */
869 u_int
870 ath_hal_getantennareduction(struct ath_hal *ah,
871     const struct ieee80211_channel *chan, u_int twiceGain)
872 {
873         int8_t antennaMax = twiceGain - chan->ic_maxantgain*2;
874         return (antennaMax < 0) ? 0 : antennaMax;
875 }