]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ath/ath_hal/ah_regdomain.c
Merge OpenSSL 1.0.2m.
[FreeBSD/FreeBSD.git] / sys / dev / 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)            nitems(a)
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,      &regDmn5GhzTurboFreq[0] },
103         { HAL_MODE_11A,         IEEE80211_CHAN_A,       &regDmn5GhzFreq[0] },
104         { HAL_MODE_11B,         IEEE80211_CHAN_B,       &regDmn2GhzFreq[0] },
105         { HAL_MODE_11G,         IEEE80211_CHAN_G,       &regDmn2Ghz11gFreq[0] },
106         { HAL_MODE_11G_TURBO,   IEEE80211_CHAN_108G,    &regDmn2Ghz11gTurboFreq[0] },
107         { HAL_MODE_11A_TURBO,   IEEE80211_CHAN_108A,    &regDmn5GhzTurboFreq[0] },
108         { HAL_MODE_11A_QUARTER_RATE,
109           IEEE80211_CHAN_A | IEEE80211_CHAN_QUARTER,    &regDmn5GhzFreq[0] },
110         { HAL_MODE_11A_HALF_RATE,
111           IEEE80211_CHAN_A | IEEE80211_CHAN_HALF,       &regDmn5GhzFreq[0] },
112         { HAL_MODE_11G_QUARTER_RATE,
113           IEEE80211_CHAN_G | IEEE80211_CHAN_QUARTER,    &regDmn2Ghz11gFreq[0] },
114         { HAL_MODE_11G_HALF_RATE,
115           IEEE80211_CHAN_G | IEEE80211_CHAN_HALF,       &regDmn2Ghz11gFreq[0] },
116         { HAL_MODE_11NG_HT20,
117           IEEE80211_CHAN_G | IEEE80211_CHAN_HT20,       &regDmn2Ghz11gFreq[0] },
118         { HAL_MODE_11NG_HT40PLUS,
119           IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U,      &regDmn2Ghz11gFreq[0] },
120         { HAL_MODE_11NG_HT40MINUS,
121           IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D,      &regDmn2Ghz11gFreq[0] },
122         { HAL_MODE_11NA_HT20,
123           IEEE80211_CHAN_A | IEEE80211_CHAN_HT20,       &regDmn5GhzFreq[0] },
124         { HAL_MODE_11NA_HT40PLUS,
125           IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U,      &regDmn5GhzFreq[0] },
126         { HAL_MODE_11NA_HT40MINUS,
127           IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D,      &regDmn5GhzFreq[0] },
128 };
129
130 static void ath_hal_update_dfsdomain(struct ath_hal *ah);
131
132 static OS_INLINE uint16_t
133 getEepromRD(struct ath_hal *ah)
134 {
135         return AH_PRIVATE(ah)->ah_currentRD &~ WORLDWIDE_ROAMING_FLAG;
136 }
137
138 /*
139  * Test to see if the bitmask array is all zeros
140  */
141 static HAL_BOOL
142 isChanBitMaskZero(const uint64_t *bitmask)
143 {
144 #if BMLEN > 2
145 #error  "add more cases"
146 #endif
147 #if BMLEN > 1
148         if (bitmask[1] != 0)
149                 return AH_FALSE;
150 #endif
151         return (bitmask[0] == 0);
152 }
153
154 /*
155  * Return whether or not the regulatory domain/country in EEPROM
156  * is acceptable.
157  */
158 static HAL_BOOL
159 isEepromValid(struct ath_hal *ah)
160 {
161         uint16_t rd = getEepromRD(ah);
162         int i;
163
164         if (rd & COUNTRY_ERD_FLAG) {
165                 uint16_t cc = rd &~ COUNTRY_ERD_FLAG;
166                 for (i = 0; i < N(allCountries); i++)
167                         if (allCountries[i].countryCode == cc)
168                                 return AH_TRUE;
169         } else {
170                 for (i = 0; i < N(regDomainPairs); i++)
171                         if (regDomainPairs[i].regDmnEnum == rd)
172                                 return AH_TRUE;
173         }
174
175         if (rd == FCC_UBNT) {
176                 return AH_TRUE;
177         }
178
179         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
180             "%s: invalid regulatory domain/country code 0x%x\n", __func__, rd);
181         return AH_FALSE;
182 }
183
184 /*
185  * Find the pointer to the country element in the country table
186  * corresponding to the country code
187  */
188 static COUNTRY_CODE_TO_ENUM_RD*
189 findCountry(HAL_CTRY_CODE countryCode)
190 {
191         int i;
192
193         for (i = 0; i < N(allCountries); i++) {
194                 if (allCountries[i].countryCode == countryCode)
195                         return &allCountries[i];
196         }
197         return AH_NULL;
198 }
199
200 static REG_DOMAIN *
201 findRegDmn(int regDmn)
202 {
203         int i;
204
205         for (i = 0; i < N(regDomains); i++) {
206                 if (regDomains[i].regDmnEnum == regDmn)
207                         return &regDomains[i];
208         }
209         return AH_NULL;
210 }
211
212 static REG_DMN_PAIR_MAPPING *
213 findRegDmnPair(int regDmnPair)
214 {
215         int i;
216
217         if (regDmnPair != NO_ENUMRD) {
218                 for (i = 0; i < N(regDomainPairs); i++) {
219                         if (regDomainPairs[i].regDmnEnum == regDmnPair)
220                                 return &regDomainPairs[i];
221                 }
222         }
223         return AH_NULL;
224 }
225
226 /*
227  * Calculate a default country based on the EEPROM setting.
228  */
229 static HAL_CTRY_CODE
230 getDefaultCountry(struct ath_hal *ah)
231 {
232         REG_DMN_PAIR_MAPPING *regpair;
233         uint16_t rd;
234
235         rd = getEepromRD(ah);
236         if (rd & COUNTRY_ERD_FLAG) {
237                 COUNTRY_CODE_TO_ENUM_RD *country;
238                 uint16_t cc = rd & ~COUNTRY_ERD_FLAG;
239                 country = findCountry(cc);
240                 if (country != AH_NULL)
241                         return cc;
242         }
243         /*
244          * Check reg domains that have only one country
245          */
246         regpair = findRegDmnPair(rd);
247         return (regpair != AH_NULL) ? regpair->singleCC : CTRY_DEFAULT;
248 }
249
250 static HAL_BOOL
251 IS_BIT_SET(int bit, const uint64_t bitmask[])
252 {
253         int byteOffset, bitnum;
254         uint64_t val;
255
256         byteOffset = bit/64;
257         bitnum = bit - byteOffset*64;
258         val = ((uint64_t) 1) << bitnum;
259         return (bitmask[byteOffset] & val) != 0;
260 }
261
262 static HAL_STATUS
263 getregstate(struct ath_hal *ah, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
264     COUNTRY_CODE_TO_ENUM_RD **pcountry,
265     REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz)
266 {
267         COUNTRY_CODE_TO_ENUM_RD *country;
268         REG_DOMAIN *rd5GHz, *rd2GHz;
269
270         if (cc == CTRY_DEFAULT && regDmn == SKU_NONE) {
271                 /*
272                  * Validate the EEPROM setting and setup defaults
273                  */
274                 if (!isEepromValid(ah)) {
275                         /*
276                          * Don't return any channels if the EEPROM has an
277                          * invalid regulatory domain/country code setting.
278                          */
279                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
280                             "%s: invalid EEPROM contents\n",__func__);
281                         return HAL_EEBADREG;
282                 }
283
284                 cc = getDefaultCountry(ah);
285                 country = findCountry(cc);
286                 if (country == AH_NULL) {
287                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
288                             "NULL Country!, cc %d\n", cc);
289                         return HAL_EEBADCC;
290                 }
291                 regDmn = country->regDmnEnum;
292                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: EEPROM cc %u rd 0x%x\n",
293                     __func__, cc, regDmn);
294
295                 if (country->countryCode == CTRY_DEFAULT) {
296                         /*
297                          * Check EEPROM; SKU may be for a country, single
298                          * domain, or multiple domains (WWR).
299                          */
300                         uint16_t rdnum = getEepromRD(ah);
301                         if ((rdnum & COUNTRY_ERD_FLAG) == 0 &&
302                             (findRegDmn(rdnum) != AH_NULL ||
303                              findRegDmnPair(rdnum) != AH_NULL)) {
304                                 regDmn = rdnum;
305                                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
306                                     "%s: EEPROM rd 0x%x\n", __func__, rdnum);
307                         }
308                 }
309         } else {
310                 country = findCountry(cc);
311                 if (country == AH_NULL) {
312                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
313                             "unknown country, cc %d\n", cc);
314                         return HAL_EINVAL;
315                 }
316                 if (regDmn == SKU_NONE)
317                         regDmn = country->regDmnEnum;
318                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u rd 0x%x\n",
319                     __func__, cc, regDmn);
320         }
321
322         /*
323          * Setup per-band state.
324          */
325         if ((regDmn & MULTI_DOMAIN_MASK) == 0) {
326                 REG_DMN_PAIR_MAPPING *regpair = findRegDmnPair(regDmn);
327                 if (regpair == AH_NULL) {
328                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
329                             "%s: no reg domain pair %u for country %u\n",
330                             __func__, regDmn, country->countryCode);
331                         return HAL_EINVAL;
332                 }
333                 rd5GHz = findRegDmn(regpair->regDmn5GHz);
334                 if (rd5GHz == AH_NULL) {
335                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
336                             "%s: no 5GHz reg domain %u for country %u\n",
337                             __func__, regpair->regDmn5GHz, country->countryCode);
338                         return HAL_EINVAL;
339                 }
340                 rd2GHz = findRegDmn(regpair->regDmn2GHz);
341                 if (rd2GHz == AH_NULL) {
342                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
343                             "%s: no 2GHz reg domain %u for country %u\n",
344                             __func__, regpair->regDmn2GHz, country->countryCode);
345                         return HAL_EINVAL;
346                 }
347         } else {
348                 rd5GHz = rd2GHz = findRegDmn(regDmn);
349                 if (rd2GHz == AH_NULL) {
350                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
351                             "%s: no unitary reg domain %u for country %u\n",
352                             __func__, regDmn, country->countryCode);
353                         return HAL_EINVAL;
354                 }
355         }
356         if (pcountry != AH_NULL)
357                 *pcountry = country;
358         *prd2GHz = rd2GHz;
359         *prd5GHz = rd5GHz;
360         return HAL_OK;
361 }
362
363 static uint64_t *
364 getchannelBM(u_int mode, REG_DOMAIN *rd)
365 {
366         switch (mode) {
367         case HAL_MODE_11B:
368                 return (rd->chan11b);
369         case HAL_MODE_11G_QUARTER_RATE:
370                 return (rd->chan11g_quarter);
371         case HAL_MODE_11G_HALF_RATE:
372                 return (rd->chan11g_half);
373         case HAL_MODE_11G:
374         case HAL_MODE_11NG_HT20:
375         case HAL_MODE_11NG_HT40PLUS:
376         case HAL_MODE_11NG_HT40MINUS:
377                 return (rd->chan11g);
378         case HAL_MODE_11G_TURBO:
379                 return (rd->chan11g_turbo);
380         case HAL_MODE_11A_QUARTER_RATE:
381                 return (rd->chan11a_quarter);
382         case HAL_MODE_11A_HALF_RATE:
383                 return (rd->chan11a_half);
384         case HAL_MODE_11A:
385         case HAL_MODE_11NA_HT20:
386         case HAL_MODE_11NA_HT40PLUS:
387         case HAL_MODE_11NA_HT40MINUS:
388                 return (rd->chan11a);
389         case HAL_MODE_TURBO:
390                 return (rd->chan11a_turbo);
391         case HAL_MODE_11A_TURBO:
392                 return (rd->chan11a_dyn_turbo);
393         default:
394                 return (AH_NULL);
395         }
396 }
397
398 static void
399 setchannelflags(struct ieee80211_channel *c, REG_DMN_FREQ_BAND *fband,
400     REG_DOMAIN *rd)
401 {
402         if (fband->usePassScan & rd->pscan)
403                 c->ic_flags |= IEEE80211_CHAN_PASSIVE;
404         if (fband->useDfs & rd->dfsMask)
405                 c->ic_flags |= IEEE80211_CHAN_DFS;
406         if (IEEE80211_IS_CHAN_5GHZ(c) && (rd->flags & DISALLOW_ADHOC_11A))
407                 c->ic_flags |= IEEE80211_CHAN_NOADHOC;
408         if (IEEE80211_IS_CHAN_TURBO(c) &&
409             (rd->flags & DISALLOW_ADHOC_11A_TURB))
410                 c->ic_flags |= IEEE80211_CHAN_NOADHOC;
411         if (rd->flags & NO_HOSTAP)
412                 c->ic_flags |= IEEE80211_CHAN_NOHOSTAP;
413         if (rd->flags & LIMIT_FRAME_4MS)
414                 c->ic_flags |= IEEE80211_CHAN_4MSXMIT;
415         if (rd->flags & NEED_NFC)
416                 c->ic_flags |= CHANNEL_NFCREQUIRED;
417 }
418
419 static int
420 addchan(struct ath_hal *ah, struct ieee80211_channel chans[],
421     u_int maxchans, int *nchans, uint16_t freq, uint32_t flags,
422     REG_DMN_FREQ_BAND *fband, REG_DOMAIN *rd)
423 {
424         struct ieee80211_channel *c;
425
426         if (*nchans >= maxchans)
427                 return (HAL_ENOMEM);
428
429         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
430             "%s: %d: freq=%d, flags=0x%08x\n",
431             __func__, *nchans, (int) freq, flags);
432
433         c = &chans[(*nchans)++];
434         c->ic_freq = freq;
435         c->ic_flags = flags;
436         setchannelflags(c, fband, rd);
437         c->ic_maxregpower = fband->powerDfs;
438         ath_hal_getpowerlimits(ah, c);
439         c->ic_maxantgain = fband->antennaMax;
440
441         return (0);
442 }
443
444 static int
445 copychan_prev(struct ath_hal *ah, struct ieee80211_channel chans[],
446     u_int maxchans, int *nchans, uint16_t freq, uint32_t flags)
447 {
448         struct ieee80211_channel *c;
449
450         if (*nchans == 0)
451                 return (HAL_EINVAL);
452
453         if (*nchans >= maxchans)
454                 return (HAL_ENOMEM);
455
456         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
457             "%s: %d: freq=%d, flags=0x%08x\n",
458             __func__, *nchans, (int) freq, flags);
459
460         c = &chans[(*nchans)++];
461         c[0] = c[-1];
462         c->ic_freq = freq;
463         /* XXX is it needed here? */
464         ath_hal_getpowerlimits(ah, c);
465
466         return (0);
467 }
468
469 static int
470 add_chanlist_band(struct ath_hal *ah, struct ieee80211_channel chans[],
471     int maxchans, int *nchans, uint16_t freq_lo, uint16_t freq_hi, int step,
472     uint32_t flags, REG_DMN_FREQ_BAND *fband, REG_DOMAIN *rd)
473 {
474         uint16_t freq = freq_lo;
475         int error;
476
477         if (freq_hi < freq_lo)
478                 return (0);
479
480         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
481             "%s: freq=%d..%d, flags=0x%08x, step=%d\n", __func__,
482             (int) freq_lo, (int) freq_hi, flags, step);
483
484         error = addchan(ah, chans, maxchans, nchans, freq, flags, fband, rd);
485         for (freq += step; freq <= freq_hi && error == 0; freq += step)
486                 error = copychan_prev(ah, chans, maxchans, nchans, freq, flags);
487
488         return (error);
489 }
490
491 static void
492 adj_freq_ht40(u_int mode, int *low_adj, int *hi_adj, int *channelSep)
493 {
494
495         *low_adj = *hi_adj = *channelSep = 0;
496         switch (mode) {
497         case HAL_MODE_11NA_HT40PLUS:
498                 *channelSep = 40;
499                 /* FALLTHROUGH */
500         case HAL_MODE_11NG_HT40PLUS:
501                 *hi_adj = -20;
502                 break;
503         case HAL_MODE_11NA_HT40MINUS:
504                 *channelSep = 40;
505                 /* FALLTHROUGH */
506         case HAL_MODE_11NG_HT40MINUS:
507                 *low_adj = 20;
508                 break;
509         }
510 }
511
512 static void
513 add_chanlist_mode(struct ath_hal *ah, struct ieee80211_channel chans[],
514     u_int maxchans, int *nchans, const struct cmode *cm, REG_DOMAIN *rd,
515     HAL_BOOL enableExtendedChannels)
516 {
517         uint64_t *channelBM;
518         uint16_t freq_lo, freq_hi;
519         int b, error, low_adj, hi_adj, channelSep;
520
521         if (!ath_hal_getChannelEdges(ah, cm->flags, &freq_lo, &freq_hi)) {
522                 /* channel not supported by hardware, skip it */
523                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
524                     "%s: channels 0x%x not supported by hardware\n",
525                     __func__, cm->flags);
526                 return;
527         }
528
529         channelBM = getchannelBM(cm->mode, rd);
530         if (isChanBitMaskZero(channelBM))
531                 return;
532
533         /*
534          * Setup special handling for HT40 channels; e.g.
535          * 5G HT40 channels require 40Mhz channel separation.
536          */
537         adj_freq_ht40(cm->mode, &low_adj, &hi_adj, &channelSep);
538
539         for (b = 0; b < 64*BMLEN; b++) {
540                 REG_DMN_FREQ_BAND *fband;
541                 uint16_t bfreq_lo, bfreq_hi;
542                 int step;
543
544                 if (!IS_BIT_SET(b, channelBM))
545                         continue;
546                 fband = &cm->freqs[b];
547
548                 if ((fband->usePassScan & IS_ECM_CHAN) &&
549                     !enableExtendedChannels) {
550                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
551                             "skip ecm channels\n");
552                         continue;
553                 }
554 #if 0
555                 if ((fband->useDfs & rd->dfsMask) && 
556                     (cm->flags & IEEE80211_CHAN_HT40)) {
557                         /* NB: DFS and HT40 don't mix */
558                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
559                             "skip HT40 chan, DFS required\n");
560                         continue;
561                 }
562 #endif
563                 /*
564                  * XXX TODO: handle REG_EXT_FCC_CH_144.
565                  *
566                  * Figure out which instances/uses cause us to not
567                  * be allowed to use channel 144 (pri or sec overlap.)
568                  */
569
570                 bfreq_lo = MAX(fband->lowChannel + low_adj, freq_lo);
571                 bfreq_hi = MIN(fband->highChannel + hi_adj, freq_hi);
572
573                 /*
574                  * Don't start the 5GHz channel list at 5120MHz.
575                  *
576                  * Unfortunately (sigh) the HT40 channel creation
577                  * logic will create HT40U channels at 5120, 5160, 5200.
578                  * This means that 36 (5180) isn't considered as a
579                  * HT40 channel, and everything goes messed up from there.
580                  */
581                 if ((cm->flags & IEEE80211_CHAN_5GHZ) &&
582                     (cm->flags & IEEE80211_CHAN_HT40U)) {
583                         if (bfreq_lo < 5180)
584                                 bfreq_lo = 5180;
585                 }
586
587                 /*
588                  * Same with HT40D - need to start at 5200 or the low
589                  * channels are all wrong again.
590                  */
591                 if ((cm->flags & IEEE80211_CHAN_5GHZ) &&
592                     (cm->flags & IEEE80211_CHAN_HT40D)) {
593                         if (bfreq_lo < 5200)
594                                 bfreq_lo = 5200;
595                 }
596
597                 if (fband->channelSep >= channelSep)
598                         step = fband->channelSep;
599                 else
600                         step = roundup(channelSep, fband->channelSep);
601
602                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
603                     "%s: freq_lo=%d, freq_hi=%d, low_adj=%d, hi_adj=%d, "
604                     "bandlo=%d, bandhi=%d, bfreqlo=%d, bfreqhi=%d, step=%d, "
605                     "flags=0x%08x\n",
606                     __func__,
607                     (int) freq_lo,
608                     (int) freq_hi,
609                     (int) low_adj,
610                     (int) hi_adj,
611                     (int) fband->lowChannel,
612                     (int) fband->highChannel,
613                     (int) bfreq_lo,
614                     (int) bfreq_hi,
615                     step,
616                     (int) cm->flags);
617
618                 error = add_chanlist_band(ah, chans, maxchans, nchans,
619                     bfreq_lo, bfreq_hi, step, cm->flags, fband, rd);
620                 if (error != 0) {
621                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
622                             "%s: too many channels for channel table\n",
623                             __func__);
624                         return;
625                 }
626         }
627 }
628
629 static u_int
630 getmodesmask(struct ath_hal *ah, REG_DOMAIN *rd5GHz, u_int modeSelect)
631 {
632 #define HAL_MODE_11A_ALL \
633         (HAL_MODE_11A | HAL_MODE_11A_TURBO | HAL_MODE_TURBO | \
634          HAL_MODE_11A_QUARTER_RATE | HAL_MODE_11A_HALF_RATE)
635         u_int modesMask;
636
637         /* get modes that HW is capable of */
638         modesMask = ath_hal_getWirelessModes(ah);
639         modesMask &= modeSelect;
640         /* optimize work below if no 11a channels */
641         if (isChanBitMaskZero(rd5GHz->chan11a) &&
642             (modesMask & HAL_MODE_11A_ALL)) {
643                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
644                     "%s: disallow all 11a\n", __func__);
645                 modesMask &= ~HAL_MODE_11A_ALL;
646         }
647
648         return (modesMask);
649 #undef HAL_MODE_11A_ALL
650 }
651
652 /*
653  * Construct the channel list for the specified regulatory config.
654  */
655 static HAL_STATUS
656 getchannels(struct ath_hal *ah,
657     struct ieee80211_channel chans[], u_int maxchans, int *nchans,
658     u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
659     HAL_BOOL enableExtendedChannels,
660     COUNTRY_CODE_TO_ENUM_RD **pcountry,
661     REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz)
662 {
663         REG_DOMAIN *rd5GHz, *rd2GHz;
664         u_int modesMask;
665         const struct cmode *cm;
666         HAL_STATUS status;
667
668         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u regDmn 0x%x mode 0x%x%s\n",
669             __func__, cc, regDmn, modeSelect, 
670             enableExtendedChannels ? " ecm" : "");
671
672         status = getregstate(ah, cc, regDmn, pcountry, &rd2GHz, &rd5GHz);
673         if (status != HAL_OK)
674                 return status;
675
676         modesMask = getmodesmask(ah, rd5GHz, modeSelect);
677         /* XXX error? */
678         if (modesMask == 0)
679                 goto done;
680
681         for (cm = modes; cm < &modes[N(modes)]; cm++) {
682                 REG_DOMAIN *rd;
683
684                 if ((cm->mode & modesMask) == 0) {
685                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
686                             "%s: skip mode 0x%x flags 0x%x\n",
687                             __func__, cm->mode, cm->flags);
688                         continue;
689                 }
690
691                 if (cm->flags & IEEE80211_CHAN_5GHZ)
692                         rd = rd5GHz;
693                 else if (cm->flags & IEEE80211_CHAN_2GHZ)
694                         rd = rd2GHz;
695                 else {
696                         ath_hal_printf(ah, "%s: Unkonwn HAL flags 0x%x\n",
697                             __func__, cm->flags);
698                         return HAL_EINVAL;
699                 }
700
701                 add_chanlist_mode(ah, chans, maxchans, nchans, cm,
702                     rd, enableExtendedChannels);
703                 if (*nchans >= maxchans)
704                         goto done;
705         }
706 done:
707         /* NB: pcountry set above by getregstate */
708         if (prd2GHz != AH_NULL)
709                 *prd2GHz = rd2GHz;
710         if (prd5GHz != AH_NULL)
711                 *prd5GHz = rd5GHz;
712         return HAL_OK;
713 }
714
715 /*
716  * Retrieve a channel list without affecting runtime state.
717  */
718 HAL_STATUS
719 ath_hal_getchannels(struct ath_hal *ah,
720     struct ieee80211_channel chans[], u_int maxchans, int *nchans,
721     u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
722     HAL_BOOL enableExtendedChannels)
723 {
724         return getchannels(ah, chans, maxchans, nchans, modeSelect,
725             cc, regDmn, enableExtendedChannels, AH_NULL, AH_NULL, AH_NULL);
726 }
727
728 /*
729  * Handle frequency mapping from 900Mhz range to 2.4GHz range
730  * for GSM radios.  This is done when we need the h/w frequency
731  * and the channel is marked IEEE80211_CHAN_GSM.
732  */
733 static int
734 ath_hal_mapgsm(int sku, int freq)
735 {
736         if (sku == SKU_XR9)
737                 return 1520 + freq;
738         if (sku == SKU_GZ901)
739                 return 1544 + freq;
740         if (sku == SKU_SR9)
741                 return 3344 - freq;
742         if (sku == SKU_XC900M)
743                 return 1517 + freq;
744         HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
745             "%s: cannot map freq %u unknown gsm sku %u\n",
746             __func__, freq, sku);
747         return freq;
748 }
749
750 /*
751  * Setup the internal/private channel state given a table of
752  * net80211 channels.  We collapse entries for the same frequency
753  * and record the frequency for doing noise floor processing
754  * where we don't have net80211 channel context.
755  */
756 static HAL_BOOL
757 assignPrivateChannels(struct ath_hal *ah,
758         struct ieee80211_channel chans[], int nchans, int sku)
759 {
760         HAL_CHANNEL_INTERNAL *ic;
761         int i, j, next, freq;
762
763         next = 0;
764         for (i = 0; i < nchans; i++) {
765                 struct ieee80211_channel *c = &chans[i];
766                 for (j = i-1; j >= 0; j--)
767                         if (chans[j].ic_freq == c->ic_freq) {
768                                 c->ic_devdata = chans[j].ic_devdata;
769                                 break;
770                         }
771                 if (j < 0) {
772                         /* new entry, assign a private channel entry */
773                         if (next >= N(AH_PRIVATE(ah)->ah_channels)) {
774                                 HALDEBUG(ah, HAL_DEBUG_ANY,
775                                     "%s: too many channels, max %zu\n",
776                                     __func__, N(AH_PRIVATE(ah)->ah_channels));
777                                 return AH_FALSE;
778                         }
779                         /*
780                          * Handle frequency mapping for 900MHz devices.
781                          * The hardware uses 2.4GHz frequencies that are
782                          * down-converted.  The 802.11 layer uses the
783                          * true frequencies.
784                          */
785                         freq = IEEE80211_IS_CHAN_GSM(c) ?
786                             ath_hal_mapgsm(sku, c->ic_freq) : c->ic_freq;
787
788                         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
789                             "%s: private[%3u] %u/0x%x -> channel %u\n",
790                             __func__, next, c->ic_freq, c->ic_flags, freq);
791
792                         ic = &AH_PRIVATE(ah)->ah_channels[next];
793                         /*
794                          * NB: This clears privFlags which means ancillary
795                          *     code like ANI and IQ calibration will be
796                          *     restarted and re-setup any per-channel state.
797                          */
798                         OS_MEMZERO(ic, sizeof(*ic));
799                         ic->channel = freq;
800                         c->ic_devdata = next;
801                         next++;
802                 }
803         }
804         AH_PRIVATE(ah)->ah_nchan = next;
805         HALDEBUG(ah, HAL_DEBUG_ANY, "%s: %u public, %u private channels\n",
806             __func__, nchans, next);
807         return AH_TRUE;
808 }
809
810 /*
811  * Setup the channel list based on the information in the EEPROM.
812  */
813 HAL_STATUS
814 ath_hal_init_channels(struct ath_hal *ah,
815     struct ieee80211_channel chans[], u_int maxchans, int *nchans,
816     u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
817     HAL_BOOL enableExtendedChannels)
818 {
819         COUNTRY_CODE_TO_ENUM_RD *country;
820         REG_DOMAIN *rd5GHz, *rd2GHz;
821         HAL_STATUS status;
822
823         status = getchannels(ah, chans, maxchans, nchans, modeSelect,
824             cc, regDmn, enableExtendedChannels, &country, &rd2GHz, &rd5GHz);
825         if (status == HAL_OK &&
826             assignPrivateChannels(ah, chans, *nchans, AH_PRIVATE(ah)->ah_currentRD)) {
827                 AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz;
828                 AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz;
829
830                 ah->ah_countryCode = country->countryCode;
831                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n",
832                     __func__, ah->ah_countryCode);
833
834                 /* Update current DFS domain */
835                 ath_hal_update_dfsdomain(ah);
836         } else
837                 status = HAL_EINVAL;
838
839         return status;
840 }
841
842 /*
843  * Set the channel list.
844  */
845 HAL_STATUS
846 ath_hal_set_channels(struct ath_hal *ah,
847     struct ieee80211_channel chans[], int nchans,
848     HAL_CTRY_CODE cc, HAL_REG_DOMAIN rd)
849 {
850         COUNTRY_CODE_TO_ENUM_RD *country;
851         REG_DOMAIN *rd5GHz, *rd2GHz;
852         HAL_STATUS status;
853
854         switch (rd) {
855         case SKU_SR9:
856         case SKU_XR9:
857         case SKU_GZ901:
858         case SKU_XC900M:
859                 /*
860                  * Map 900MHz sku's.  The frequencies will be mapped
861                  * according to the sku to compensate for the down-converter.
862                  * We use the FCC for these sku's as the mapped channel
863                  * list is known compatible (will need to change if/when
864                  * vendors do different mapping in different locales).
865                  */
866                 status = getregstate(ah, CTRY_DEFAULT, SKU_FCC,
867                     &country, &rd2GHz, &rd5GHz);
868                 break;
869         default:
870                 status = getregstate(ah, cc, rd,
871                     &country, &rd2GHz, &rd5GHz);
872                 rd = AH_PRIVATE(ah)->ah_currentRD;
873                 break;
874         }
875         if (status == HAL_OK && assignPrivateChannels(ah, chans, nchans, rd)) {
876                 AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz;
877                 AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz;
878
879                 ah->ah_countryCode = country->countryCode;
880                 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n",
881                     __func__, ah->ah_countryCode);
882         } else
883                 status = HAL_EINVAL;
884
885         if (status == HAL_OK) {
886                 /* Update current DFS domain */
887                 (void) ath_hal_update_dfsdomain(ah);
888         }
889         return status;
890 }
891
892 #ifdef AH_DEBUG
893 /*
894  * Return the internal channel corresponding to a public channel.
895  * NB: normally this routine is inline'd (see ah_internal.h)
896  */
897 HAL_CHANNEL_INTERNAL *
898 ath_hal_checkchannel(struct ath_hal *ah, const struct ieee80211_channel *c)
899 {
900         HAL_CHANNEL_INTERNAL *cc = &AH_PRIVATE(ah)->ah_channels[c->ic_devdata];
901
902         if (c->ic_devdata < AH_PRIVATE(ah)->ah_nchan &&
903             (c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c)))
904                 return cc;
905         if (c->ic_devdata >= AH_PRIVATE(ah)->ah_nchan) {
906                 HALDEBUG(ah, HAL_DEBUG_ANY,
907                     "%s: bad mapping, devdata %u nchans %u\n",
908                    __func__, c->ic_devdata, AH_PRIVATE(ah)->ah_nchan);
909                 HALASSERT(c->ic_devdata < AH_PRIVATE(ah)->ah_nchan);
910         } else {
911                 HALDEBUG(ah, HAL_DEBUG_ANY,
912                     "%s: no match for %u/0x%x devdata %u channel %u\n",
913                    __func__, c->ic_freq, c->ic_flags, c->ic_devdata,
914                    cc->channel);
915                 HALASSERT(c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c));
916         }
917         return AH_NULL;
918 }
919 #endif /* AH_DEBUG */
920
921 #define isWwrSKU(_ah) \
922         ((getEepromRD((_ah)) & WORLD_SKU_MASK) == WORLD_SKU_PREFIX || \
923           getEepromRD(_ah) == WORLD)
924
925 /*
926  * Return the test group for the specific channel based on
927  * the current regulatory setup.
928  */
929 u_int
930 ath_hal_getctl(struct ath_hal *ah, const struct ieee80211_channel *c)
931 {
932         u_int ctl;
933
934         if (AH_PRIVATE(ah)->ah_rd2GHz == AH_PRIVATE(ah)->ah_rd5GHz ||
935             (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)))
936                 ctl = SD_NO_CTL;
937         else if (IEEE80211_IS_CHAN_2GHZ(c))
938                 ctl = AH_PRIVATE(ah)->ah_rd2GHz->conformanceTestLimit;
939         else
940                 ctl = AH_PRIVATE(ah)->ah_rd5GHz->conformanceTestLimit;
941         if (IEEE80211_IS_CHAN_B(c))
942                 return ctl | CTL_11B;
943         if (IEEE80211_IS_CHAN_G(c))
944                 return ctl | CTL_11G;
945         if (IEEE80211_IS_CHAN_108G(c))
946                 return ctl | CTL_108G;
947         if (IEEE80211_IS_CHAN_TURBO(c))
948                 return ctl | CTL_TURBO;
949         if (IEEE80211_IS_CHAN_A(c))
950                 return ctl | CTL_11A;
951         return ctl;
952 }
953
954
955 /*
956  * Update the current dfsDomain setting based on the given
957  * country code.
958  *
959  * Since FreeBSD/net80211 allows the channel set to change
960  * after the card has been setup (via ath_hal_init_channels())
961  * this function method is needed to update ah_dfsDomain.
962  */
963 void
964 ath_hal_update_dfsdomain(struct ath_hal *ah)
965 {
966         const REG_DOMAIN *rd5GHz = AH_PRIVATE(ah)->ah_rd5GHz;
967         HAL_DFS_DOMAIN dfsDomain = HAL_DFS_UNINIT_DOMAIN;
968
969         if (rd5GHz->dfsMask & DFS_FCC3)
970                 dfsDomain = HAL_DFS_FCC_DOMAIN;
971         if (rd5GHz->dfsMask & DFS_ETSI)
972                 dfsDomain = HAL_DFS_ETSI_DOMAIN;
973         if (rd5GHz->dfsMask & DFS_MKK4)
974                 dfsDomain = HAL_DFS_MKK4_DOMAIN;
975         AH_PRIVATE(ah)->ah_dfsDomain = dfsDomain;
976         HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s ah_dfsDomain: %d\n",
977             __func__, AH_PRIVATE(ah)->ah_dfsDomain);
978 }
979
980
981 /*
982  * Return the max allowed antenna gain and apply any regulatory
983  * domain specific changes.
984  *
985  * NOTE: a negative reduction is possible in RD's that only
986  * measure radiated power (e.g., ETSI) which would increase
987  * that actual conducted output power (though never beyond
988  * the calibrated target power).
989  */
990 u_int
991 ath_hal_getantennareduction(struct ath_hal *ah,
992     const struct ieee80211_channel *chan, u_int twiceGain)
993 {
994         int8_t antennaMax = twiceGain - chan->ic_maxantgain*2;
995         return (antennaMax < 0) ? 0 : antennaMax;
996 }