ath9k: Add new Atheros IEEE 802.11n driver
[pandora-kernel.git] / drivers / net / wireless / ath9k / regd.c
1 /*
2  * Copyright (c) 2008 Atheros Communications Inc.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/slab.h>
19 #include "core.h"
20 #include "hw.h"
21 #include "regd.h"
22 #include "regd_common.h"
23
24 static int ath9k_regd_chansort(const void *a, const void *b)
25 {
26         const struct ath9k_channel *ca = a;
27         const struct ath9k_channel *cb = b;
28
29         return (ca->channel == cb->channel) ?
30             (ca->channelFlags & CHAN_FLAGS) -
31             (cb->channelFlags & CHAN_FLAGS) : ca->channel - cb->channel;
32 }
33
34 static void
35 ath9k_regd_sort(void *a, u32 n, u32 size, ath_hal_cmp_t *cmp)
36 {
37         u8 *aa = a;
38         u8 *ai, *t;
39
40         for (ai = aa + size; --n >= 1; ai += size)
41                 for (t = ai; t > aa; t -= size) {
42                         u8 *u = t - size;
43                         if (cmp(u, t) <= 0)
44                                 break;
45                         swap(u, t, size);
46                 }
47 }
48
49 static u16 ath9k_regd_get_eepromRD(struct ath_hal *ah)
50 {
51         return ah->ah_currentRD & ~WORLDWIDE_ROAMING_FLAG;
52 }
53
54 static bool ath9k_regd_is_chan_bm_zero(u64 *bitmask)
55 {
56         int i;
57
58         for (i = 0; i < BMLEN; i++) {
59                 if (bitmask[i] != 0)
60                         return false;
61         }
62         return true;
63 }
64
65 static bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah)
66 {
67         u16 rd = ath9k_regd_get_eepromRD(ah);
68         int i;
69
70         if (rd & COUNTRY_ERD_FLAG) {
71                 u16 cc = rd & ~COUNTRY_ERD_FLAG;
72                 for (i = 0; i < ARRAY_SIZE(allCountries); i++)
73                         if (allCountries[i].countryCode == cc)
74                                 return true;
75         } else {
76                 for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
77                         if (regDomainPairs[i].regDmnEnum == rd)
78                                 return true;
79         }
80         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
81                  "%s: invalid regulatory domain/country code 0x%x\n",
82                  __func__, rd);
83         return false;
84 }
85
86 static bool ath9k_regd_is_fcc_midband_supported(struct ath_hal *ah)
87 {
88         u32 regcap;
89
90         regcap = ah->ah_caps.halRegCap;
91
92         if (regcap & AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND)
93                 return true;
94         else
95                 return false;
96 }
97
98 static bool ath9k_regd_is_ccode_valid(struct ath_hal *ah,
99                                       u16 cc)
100 {
101         u16 rd;
102         int i;
103
104         if (cc == CTRY_DEFAULT)
105                 return true;
106         if (cc == CTRY_DEBUG)
107                 return true;
108
109         rd = ath9k_regd_get_eepromRD(ah);
110         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: EEPROM regdomain 0x%x\n",
111                  __func__, rd);
112
113         if (rd & COUNTRY_ERD_FLAG) {
114                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
115                         "%s: EEPROM setting is country code %u\n",
116                         __func__, rd & ~COUNTRY_ERD_FLAG);
117                 return cc == (rd & ~COUNTRY_ERD_FLAG);
118         }
119
120         for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
121                 if (cc == allCountries[i].countryCode) {
122 #ifdef AH_SUPPORT_11D
123                         if ((rd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)
124                                 return true;
125 #endif
126                         if (allCountries[i].regDmnEnum == rd ||
127                             rd == DEBUG_REG_DMN || rd == NO_ENUMRD)
128                                 return true;
129                 }
130         }
131         return false;
132 }
133
134 static u32
135 ath9k_regd_get_wmodes_nreg(struct ath_hal *ah,
136                            struct country_code_to_enum_rd *country,
137                            struct regDomain *rd5GHz)
138 {
139         u32 modesAvail;
140
141         modesAvail = ah->ah_caps.halWirelessModes;
142
143         if ((modesAvail & ATH9K_MODE_SEL_11G) && (!country->allow11g))
144                 modesAvail &= ~ATH9K_MODE_SEL_11G;
145         if ((modesAvail & ATH9K_MODE_SEL_11A) &&
146             (ath9k_regd_is_chan_bm_zero(rd5GHz->chan11a)))
147                 modesAvail &= ~ATH9K_MODE_SEL_11A;
148
149         if ((modesAvail & ATH9K_MODE_SEL_11NG_HT20)
150             && (!country->allow11ng20))
151                 modesAvail &= ~ATH9K_MODE_SEL_11NG_HT20;
152
153         if ((modesAvail & ATH9K_MODE_SEL_11NA_HT20)
154             && (!country->allow11na20))
155                 modesAvail &= ~ATH9K_MODE_SEL_11NA_HT20;
156
157         if ((modesAvail & ATH9K_MODE_SEL_11NG_HT40PLUS) &&
158             (!country->allow11ng40))
159                 modesAvail &= ~ATH9K_MODE_SEL_11NG_HT40PLUS;
160
161         if ((modesAvail & ATH9K_MODE_SEL_11NG_HT40MINUS) &&
162             (!country->allow11ng40))
163                 modesAvail &= ~ATH9K_MODE_SEL_11NG_HT40MINUS;
164
165         if ((modesAvail & ATH9K_MODE_SEL_11NA_HT40PLUS) &&
166             (!country->allow11na40))
167                 modesAvail &= ~ATH9K_MODE_SEL_11NA_HT40PLUS;
168
169         if ((modesAvail & ATH9K_MODE_SEL_11NA_HT40MINUS) &&
170             (!country->allow11na40))
171                 modesAvail &= ~ATH9K_MODE_SEL_11NA_HT40MINUS;
172
173         return modesAvail;
174 }
175
176 bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah)
177 {
178         u16 rd;
179
180         rd = ath9k_regd_get_eepromRD(ah);
181
182         switch (rd) {
183         case FCC4_FCCA:
184         case (CTRY_UNITED_STATES_FCC49 | COUNTRY_ERD_FLAG):
185                 return true;
186         case DEBUG_REG_DMN:
187         case NO_ENUMRD:
188                 if (ah->ah_countryCode == CTRY_UNITED_STATES_FCC49)
189                         return true;
190                 break;
191         }
192         return false;
193 }
194
195 static struct country_code_to_enum_rd*
196 ath9k_regd_find_country(u16 countryCode)
197 {
198         int i;
199
200         for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
201                 if (allCountries[i].countryCode == countryCode)
202                         return &allCountries[i];
203         }
204         return NULL;
205 }
206
207 static u16 ath9k_regd_get_default_country(struct ath_hal *ah)
208 {
209         u16 rd;
210         int i;
211
212         rd = ath9k_regd_get_eepromRD(ah);
213         if (rd & COUNTRY_ERD_FLAG) {
214                 struct country_code_to_enum_rd *country = NULL;
215                 u16 cc = rd & ~COUNTRY_ERD_FLAG;
216
217                 country = ath9k_regd_find_country(cc);
218                 if (country != NULL)
219                         return cc;
220         }
221
222         for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
223                 if (regDomainPairs[i].regDmnEnum == rd) {
224                         if (regDomainPairs[i].singleCC != 0)
225                                 return regDomainPairs[i].singleCC;
226                         else
227                                 i = ARRAY_SIZE(regDomainPairs);
228                 }
229         return CTRY_DEFAULT;
230 }
231
232 static bool ath9k_regd_is_valid_reg_domain(int regDmn,
233                                            struct regDomain *rd)
234 {
235         int i;
236
237         for (i = 0; i < ARRAY_SIZE(regDomains); i++) {
238                 if (regDomains[i].regDmnEnum == regDmn) {
239                         if (rd != NULL) {
240                                 memcpy(rd, &regDomains[i],
241                                        sizeof(struct regDomain));
242                         }
243                         return true;
244                 }
245         }
246         return false;
247 }
248
249 static bool ath9k_regd_is_valid_reg_domainPair(int regDmnPair)
250 {
251         int i;
252
253         if (regDmnPair == NO_ENUMRD)
254                 return false;
255         for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
256                 if (regDomainPairs[i].regDmnEnum == regDmnPair)
257                         return true;
258         }
259         return false;
260 }
261
262 static bool
263 ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn,
264                                u16 channelFlag, struct regDomain *rd)
265 {
266         int i, found;
267         u64 flags = NO_REQ;
268         struct reg_dmn_pair_mapping *regPair = NULL;
269         int regOrg;
270
271         regOrg = regDmn;
272         if (regDmn == CTRY_DEFAULT) {
273                 u16 rdnum;
274                 rdnum = ath9k_regd_get_eepromRD(ah);
275
276                 if (!(rdnum & COUNTRY_ERD_FLAG)) {
277                         if (ath9k_regd_is_valid_reg_domain(rdnum, NULL) ||
278                             ath9k_regd_is_valid_reg_domainPair(rdnum)) {
279                                 regDmn = rdnum;
280                         }
281                 }
282         }
283
284         if ((regDmn & MULTI_DOMAIN_MASK) == 0) {
285                 for (i = 0, found = 0;
286                      (i < ARRAY_SIZE(regDomainPairs)) && (!found); i++) {
287                         if (regDomainPairs[i].regDmnEnum == regDmn) {
288                                 regPair = &regDomainPairs[i];
289                                 found = 1;
290                         }
291                 }
292                 if (!found) {
293                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
294                                 "%s: Failed to find reg domain pair %u\n",
295                                 __func__, regDmn);
296                         return false;
297                 }
298                 if (!(channelFlag & CHANNEL_2GHZ)) {
299                         regDmn = regPair->regDmn5GHz;
300                         flags = regPair->flags5GHz;
301                 }
302                 if (channelFlag & CHANNEL_2GHZ) {
303                         regDmn = regPair->regDmn2GHz;
304                         flags = regPair->flags2GHz;
305                 }
306         }
307
308         found = ath9k_regd_is_valid_reg_domain(regDmn, rd);
309         if (!found) {
310                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
311                         "%s: Failed to find unitary reg domain %u\n",
312                         __func__, regDmn);
313                 return false;
314         } else {
315                 rd->pscan &= regPair->pscanMask;
316                 if (((regOrg & MULTI_DOMAIN_MASK) == 0) &&
317                     (flags != NO_REQ)) {
318                         rd->flags = flags;
319                 }
320
321                 rd->flags &= (channelFlag & CHANNEL_2GHZ) ?
322                     REG_DOMAIN_2GHZ_MASK : REG_DOMAIN_5GHZ_MASK;
323                 return true;
324         }
325 }
326
327 static bool ath9k_regd_is_bit_set(int bit, u64 *bitmask)
328 {
329         int byteOffset, bitnum;
330         u64 val;
331
332         byteOffset = bit / 64;
333         bitnum = bit - byteOffset * 64;
334         val = ((u64) 1) << bitnum;
335         if (bitmask[byteOffset] & val)
336                 return true;
337         else
338                 return false;
339 }
340
341 static void
342 ath9k_regd_add_reg_classid(u8 *regclassids, u32 maxregids,
343                            u32 *nregids, u8 regclassid)
344 {
345         int i;
346
347         if (regclassid == 0)
348                 return;
349
350         for (i = 0; i < maxregids; i++) {
351                 if (regclassids[i] == regclassid)
352                         return;
353                 if (regclassids[i] == 0)
354                         break;
355         }
356
357         if (i == maxregids)
358                 return;
359         else {
360                 regclassids[i] = regclassid;
361                 *nregids += 1;
362         }
363
364         return;
365 }
366
367 static bool
368 ath9k_regd_get_eeprom_reg_ext_bits(struct ath_hal *ah,
369                                    enum reg_ext_bitmap bit)
370 {
371         return (ah->ah_currentRDExt & (1 << bit)) ? true : false;
372 }
373
374 #ifdef ATH_NF_PER_CHAN
375
376 static void ath9k_regd_init_rf_buffer(struct ath9k_channel *ichans,
377                                       int nchans)
378 {
379         int i, j, next;
380
381         for (next = 0; next < nchans; next++) {
382                 for (i = 0; i < NUM_NF_READINGS; i++) {
383                         ichans[next].nfCalHist[i].currIndex = 0;
384                         ichans[next].nfCalHist[i].privNF =
385                             AR_PHY_CCA_MAX_GOOD_VALUE;
386                         ichans[next].nfCalHist[i].invalidNFcount =
387                             AR_PHY_CCA_FILTERWINDOW_LENGTH;
388                         for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
389                                 ichans[next].nfCalHist[i].nfCalBuffer[j] =
390                                     AR_PHY_CCA_MAX_GOOD_VALUE;
391                         }
392                 }
393         }
394 }
395 #endif
396
397 static int ath9k_regd_is_chan_present(struct ath_hal *ah,
398                                       u16 c)
399 {
400         int i;
401
402         for (i = 0; i < 150; i++) {
403                 if (!ah->ah_channels[i].channel)
404                         return -1;
405                 else if (ah->ah_channels[i].channel == c)
406                         return i;
407         }
408
409         return -1;
410 }
411
412 static bool
413 ath9k_regd_add_channel(struct ath_hal *ah,
414                        u16 c,
415                        u16 c_lo,
416                        u16 c_hi,
417                        u16 maxChan,
418                        u8 ctl,
419                        int pos,
420                        struct regDomain rd5GHz,
421                        struct RegDmnFreqBand *fband,
422                        struct regDomain *rd,
423                        const struct cmode *cm,
424                        struct ath9k_channel *ichans,
425                        bool enableExtendedChannels)
426 {
427         struct ath9k_channel *chan;
428         int ret;
429         u32 channelFlags = 0;
430         u8 privFlags = 0;
431
432         if (!(c_lo <= c && c <= c_hi)) {
433                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
434                         "%s: c %u out of range [%u..%u]\n",
435                         __func__, c, c_lo, c_hi);
436                 return false;
437         }
438         if ((fband->channelBW == CHANNEL_HALF_BW) &&
439             !ah->ah_caps.halChanHalfRate) {
440                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
441                         "%s: Skipping %u half rate channel\n",
442                         __func__, c);
443                 return false;
444         }
445
446         if ((fband->channelBW == CHANNEL_QUARTER_BW) &&
447             !ah->ah_caps.halChanQuarterRate) {
448                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
449                         "%s: Skipping %u quarter rate channel\n",
450                         __func__, c);
451                 return false;
452         }
453
454         if (((c + fband->channelSep) / 2) > (maxChan + HALF_MAXCHANBW)) {
455                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
456                         "%s: c %u > maxChan %u\n",
457                         __func__, c, maxChan);
458                 return false;
459         }
460
461         if ((fband->usePassScan & IS_ECM_CHAN) && !enableExtendedChannels) {
462                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
463                         "Skipping ecm channel\n");
464                 return false;
465         }
466
467         if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == ATH9K_M_HOSTAP)) {
468                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
469                         "Skipping HOSTAP channel\n");
470                 return false;
471         }
472
473         if (IS_HT40_MODE(cm->mode) &&
474             !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_FCC_DFS_HT40)) &&
475             (fband->useDfs) &&
476             (rd->conformanceTestLimit != MKK)) {
477                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
478                         "Skipping HT40 channel (en_fcc_dfs_ht40 = 0)\n");
479                 return false;
480         }
481
482         if (IS_HT40_MODE(cm->mode) &&
483             !(ath9k_regd_get_eeprom_reg_ext_bits(ah,
484                                                  REG_EXT_JAPAN_NONDFS_HT40)) &&
485             !(fband->useDfs) && (rd->conformanceTestLimit == MKK)) {
486                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
487                         "Skipping HT40 channel (en_jap_ht40 = 0)\n");
488                 return false;
489         }
490
491         if (IS_HT40_MODE(cm->mode) &&
492             !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_JAPAN_DFS_HT40)) &&
493             (fband->useDfs) &&
494             (rd->conformanceTestLimit == MKK)) {
495                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
496                         "Skipping HT40 channel (en_jap_dfs_ht40 = 0)\n");
497                 return false;
498         }
499
500         /* Calculate channel flags */
501
502         channelFlags = cm->flags;
503
504         switch (fband->channelBW) {
505         case CHANNEL_HALF_BW:
506                 channelFlags |= CHANNEL_HALF;
507                 break;
508         case CHANNEL_QUARTER_BW:
509                 channelFlags |= CHANNEL_QUARTER;
510                 break;
511         }
512
513         if (fband->usePassScan & rd->pscan)
514                 channelFlags |= CHANNEL_PASSIVE;
515         else
516                 channelFlags &= ~CHANNEL_PASSIVE;
517         if (fband->useDfs & rd->dfsMask)
518                 privFlags = CHANNEL_DFS;
519         else
520                 privFlags = 0;
521         if (rd->flags & LIMIT_FRAME_4MS)
522                 privFlags |= CHANNEL_4MS_LIMIT;
523         if (privFlags & CHANNEL_DFS)
524                 privFlags |= CHANNEL_DISALLOW_ADHOC;
525         if (rd->flags & ADHOC_PER_11D)
526                 privFlags |= CHANNEL_PER_11D_ADHOC;
527
528         if (channelFlags & CHANNEL_PASSIVE) {
529                 if ((c < 2412) || (c > 2462)) {
530                         if (rd5GHz.regDmnEnum == MKK1 ||
531                             rd5GHz.regDmnEnum == MKK2) {
532                                 u32 regcap = ah->ah_caps.halRegCap;
533                                 if (!(regcap &
534                                       (AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
535                                        AR_EEPROM_EEREGCAP_EN_KK_U2 |
536                                        AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) &&
537                                     isUNII1OddChan(c)) {
538                                         channelFlags &= ~CHANNEL_PASSIVE;
539                                 } else {
540                                         privFlags |= CHANNEL_DISALLOW_ADHOC;
541                                 }
542                         } else {
543                                 privFlags |= CHANNEL_DISALLOW_ADHOC;
544                         }
545                 }
546         }
547
548         if (cm->mode & (ATH9K_MODE_SEL_11A |
549                         ATH9K_MODE_SEL_11NA_HT20 |
550                         ATH9K_MODE_SEL_11NA_HT40PLUS |
551                         ATH9K_MODE_SEL_11NA_HT40MINUS)) {
552                 if (rd->flags & (ADHOC_NO_11A | DISALLOW_ADHOC_11A))
553                         privFlags |= CHANNEL_DISALLOW_ADHOC;
554         }
555
556         /* Fill in channel details */
557
558         ret = ath9k_regd_is_chan_present(ah, c);
559         if (ret == -1) {
560                 chan = &ah->ah_channels[pos];
561                 chan->channel = c;
562                 chan->maxRegTxPower = fband->powerDfs;
563                 chan->antennaMax = fband->antennaMax;
564                 chan->regDmnFlags = rd->flags;
565                 chan->maxTxPower = AR5416_MAX_RATE_POWER;
566                 chan->minTxPower = AR5416_MAX_RATE_POWER;
567                 chan->channelFlags = channelFlags;
568                 chan->privFlags = privFlags;
569         } else {
570                 chan = &ah->ah_channels[ret];
571                 chan->channelFlags |= channelFlags;
572                 chan->privFlags |= privFlags;
573         }
574
575         /* Set CTLs */
576
577         if ((cm->flags & CHANNEL_ALL) == CHANNEL_A)
578                 chan->conformanceTestLimit[0] = ctl;
579         else if ((cm->flags & CHANNEL_ALL) == CHANNEL_B)
580                 chan->conformanceTestLimit[1] = ctl;
581         else if ((cm->flags & CHANNEL_ALL) == CHANNEL_G)
582                 chan->conformanceTestLimit[2] = ctl;
583
584         return (ret == -1) ? true : false;
585 }
586
587 static bool ath9k_regd_japan_check(struct ath_hal *ah,
588                                    int b,
589                                    struct regDomain *rd5GHz)
590 {
591         bool skipband = false;
592         int i;
593         u32 regcap;
594
595         for (i = 0; i < ARRAY_SIZE(j_bandcheck); i++) {
596                 if (j_bandcheck[i].freqbandbit == b) {
597                         regcap = ah->ah_caps.halRegCap;
598                         if ((j_bandcheck[i].eepromflagtocheck & regcap) == 0) {
599                                 skipband = true;
600                         } else if ((regcap & AR_EEPROM_EEREGCAP_EN_KK_U2) ||
601                                   (regcap & AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) {
602                                 rd5GHz->dfsMask |= DFS_MKK4;
603                                 rd5GHz->pscan |= PSCAN_MKK3;
604                         }
605                         break;
606                 }
607         }
608
609         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
610                 "%s: Skipping %d freq band\n",
611                 __func__, j_bandcheck[i].freqbandbit);
612
613         return skipband;
614 }
615
616 bool
617 ath9k_regd_init_channels(struct ath_hal *ah,
618                          u32 maxchans,
619                          u32 *nchans, u8 *regclassids,
620                          u32 maxregids, u32 *nregids, u16 cc,
621                          u32 modeSelect, bool enableOutdoor,
622                          bool enableExtendedChannels)
623 {
624         u32 modesAvail;
625         u16 maxChan = 7000;
626         struct country_code_to_enum_rd *country = NULL;
627         struct regDomain rd5GHz, rd2GHz;
628         const struct cmode *cm;
629         struct ath9k_channel *ichans = &ah->ah_channels[0];
630         int next = 0, b;
631         u8 ctl;
632         int regdmn;
633         u16 chanSep;
634
635         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: cc %u mode 0x%x%s%s\n",
636                  __func__, cc, modeSelect,
637                  enableOutdoor ? " Enable outdoor" : " ",
638                  enableExtendedChannels ? " Enable ecm" : "");
639
640         if (!ath9k_regd_is_ccode_valid(ah, cc)) {
641                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
642                         "%s: invalid country code %d\n", __func__, cc);
643                 return false;
644         }
645
646         if (!ath9k_regd_is_eeprom_valid(ah)) {
647                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
648                         "%s: invalid EEPROM contents\n", __func__);
649                 return false;
650         }
651
652         ah->ah_countryCode = ath9k_regd_get_default_country(ah);
653
654         if (ah->ah_countryCode == CTRY_DEFAULT) {
655                 ah->ah_countryCode = cc & COUNTRY_CODE_MASK;
656                 if ((ah->ah_countryCode == CTRY_DEFAULT) &&
657                     (ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)) {
658                         ah->ah_countryCode = CTRY_UNITED_STATES;
659                 }
660         }
661
662 #ifdef AH_SUPPORT_11D
663         if (ah->ah_countryCode == CTRY_DEFAULT) {
664                 regdmn = ath9k_regd_get_eepromRD(ah);
665                 country = NULL;
666         } else {
667 #endif
668                 country = ath9k_regd_find_country(ah->ah_countryCode);
669                 if (country == NULL) {
670                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
671                                 "Country is NULL!!!!, cc= %d\n",
672                                 ah->ah_countryCode);
673                         return false;
674                 } else {
675                         regdmn = country->regDmnEnum;
676 #ifdef AH_SUPPORT_11D
677                         if (((ath9k_regd_get_eepromRD(ah) &
678                               WORLD_SKU_MASK) == WORLD_SKU_PREFIX) &&
679                             (cc == CTRY_UNITED_STATES)) {
680                                 if (!isWwrSKU_NoMidband(ah)
681                                     && ath9k_regd_is_fcc_midband_supported(ah))
682                                         regdmn = FCC3_FCCA;
683                                 else
684                                         regdmn = FCC1_FCCA;
685                         }
686 #endif
687                 }
688 #ifdef AH_SUPPORT_11D
689         }
690 #endif
691         if (!ath9k_regd_get_wmode_regdomain(ah,
692                                             regdmn,
693                                             ~CHANNEL_2GHZ,
694                                             &rd5GHz)) {
695                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
696                         "%s: couldn't find unitary "
697                         "5GHz reg domain for country %u\n",
698                         __func__, ah->ah_countryCode);
699                 return false;
700         }
701         if (!ath9k_regd_get_wmode_regdomain(ah,
702                                             regdmn,
703                                             CHANNEL_2GHZ,
704                                             &rd2GHz)) {
705                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
706                         "%s: couldn't find unitary 2GHz "
707                         "reg domain for country %u\n",
708                         __func__, ah->ah_countryCode);
709                 return false;
710         }
711
712         if (!isWwrSKU(ah) && ((rd5GHz.regDmnEnum == FCC1) ||
713                               (rd5GHz.regDmnEnum == FCC2))) {
714                 if (ath9k_regd_is_fcc_midband_supported(ah)) {
715                         if (!ath9k_regd_get_wmode_regdomain(ah,
716                                                             FCC3_FCCA,
717                                                             ~CHANNEL_2GHZ,
718                                                             &rd5GHz)) {
719                                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
720                                         "%s: couldn't find unitary 5GHz "
721                                         "reg domain for country %u\n",
722                                         __func__, ah->ah_countryCode);
723                                 return false;
724                         }
725                 }
726         }
727
728         if (country == NULL) {
729                 modesAvail = ah->ah_caps.halWirelessModes;
730         } else {
731                 modesAvail = ath9k_regd_get_wmodes_nreg(ah, country, &rd5GHz);
732                 if (!enableOutdoor)
733                         maxChan = country->outdoorChanStart;
734         }
735
736         next = 0;
737
738         if (maxchans > ARRAY_SIZE(ah->ah_channels))
739                 maxchans = ARRAY_SIZE(ah->ah_channels);
740
741         for (cm = modes; cm < &modes[ARRAY_SIZE(modes)]; cm++) {
742                 u16 c, c_hi, c_lo;
743                 u64 *channelBM = NULL;
744                 struct regDomain *rd = NULL;
745                 struct RegDmnFreqBand *fband = NULL, *freqs;
746                 int8_t low_adj = 0, hi_adj = 0;
747
748                 if ((cm->mode & modeSelect) == 0) {
749                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
750                                 "%s: skip mode 0x%x flags 0x%x\n",
751                                 __func__, cm->mode, cm->flags);
752                         continue;
753                 }
754                 if ((cm->mode & modesAvail) == 0) {
755                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
756                                 "%s: !avail mode 0x%x (0x%x) flags 0x%x\n",
757                                 __func__, modesAvail, cm->mode,
758                                 cm->flags);
759                         continue;
760                 }
761                 if (!ath9k_get_channel_edges(ah, cm->flags, &c_lo, &c_hi)) {
762                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
763                                 "%s: channels 0x%x not supported "
764                                 "by hardware\n",
765                                 __func__, cm->flags);
766                         continue;
767                 }
768
769                 switch (cm->mode) {
770                 case ATH9K_MODE_SEL_11A:
771                 case ATH9K_MODE_SEL_11NA_HT20:
772                 case ATH9K_MODE_SEL_11NA_HT40PLUS:
773                 case ATH9K_MODE_SEL_11NA_HT40MINUS:
774                         rd = &rd5GHz;
775                         channelBM = rd->chan11a;
776                         freqs = &regDmn5GhzFreq[0];
777                         ctl = rd->conformanceTestLimit;
778                         break;
779                 case ATH9K_MODE_SEL_11B:
780                         rd = &rd2GHz;
781                         channelBM = rd->chan11b;
782                         freqs = &regDmn2GhzFreq[0];
783                         ctl = rd->conformanceTestLimit | CTL_11B;
784                         break;
785                 case ATH9K_MODE_SEL_11G:
786                 case ATH9K_MODE_SEL_11NG_HT20:
787                 case ATH9K_MODE_SEL_11NG_HT40PLUS:
788                 case ATH9K_MODE_SEL_11NG_HT40MINUS:
789                         rd = &rd2GHz;
790                         channelBM = rd->chan11g;
791                         freqs = &regDmn2Ghz11gFreq[0];
792                         ctl = rd->conformanceTestLimit | CTL_11G;
793                         break;
794                 default:
795                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
796                                 "%s: Unknown HAL mode 0x%x\n", __func__,
797                                 cm->mode);
798                         continue;
799                 }
800
801                 if (ath9k_regd_is_chan_bm_zero(channelBM))
802                         continue;
803
804                 if ((cm->mode == ATH9K_MODE_SEL_11NA_HT40PLUS) ||
805                     (cm->mode == ATH9K_MODE_SEL_11NG_HT40PLUS)) {
806                         hi_adj = -20;
807                 }
808
809                 if ((cm->mode == ATH9K_MODE_SEL_11NA_HT40MINUS) ||
810                     (cm->mode == ATH9K_MODE_SEL_11NG_HT40MINUS)) {
811                         low_adj = 20;
812                 }
813
814                 /* XXX: Add a helper here instead */
815                 for (b = 0; b < 64 * BMLEN; b++) {
816                         if (ath9k_regd_is_bit_set(b, channelBM)) {
817                                 fband = &freqs[b];
818                                 if (rd5GHz.regDmnEnum == MKK1
819                                     || rd5GHz.regDmnEnum == MKK2) {
820                                         if (ath9k_regd_japan_check(ah,
821                                                                    b,
822                                                                    &rd5GHz))
823                                                 continue;
824                                 }
825
826                                 ath9k_regd_add_reg_classid(regclassids,
827                                                            maxregids,
828                                                            nregids,
829                                                            fband->
830                                                            regClassId);
831
832                                 if (IS_HT40_MODE(cm->mode) && (rd == &rd5GHz)) {
833                                         chanSep = 40;
834                                         if (fband->lowChannel == 5280)
835                                                 low_adj += 20;
836
837                                         if (fband->lowChannel == 5170)
838                                                 continue;
839                                 } else
840                                         chanSep = fband->channelSep;
841
842                                 for (c = fband->lowChannel + low_adj;
843                                      ((c <= (fband->highChannel + hi_adj)) &&
844                                       (c >= (fband->lowChannel + low_adj)));
845                                      c += chanSep) {
846                                         if (next >= maxchans) {
847                                                 DPRINTF(ah->ah_sc,
848                                                         ATH_DBG_REGULATORY,
849                                                         "%s: too many channels "
850                                                         "for channel table\n",
851                                                         __func__);
852                                                 goto done;
853                                         }
854                                         if (ath9k_regd_add_channel(ah,
855                                                    c, c_lo, c_hi,
856                                                    maxChan, ctl,
857                                                    next,
858                                                    rd5GHz,
859                                                    fband, rd, cm,
860                                                    ichans,
861                                                    enableExtendedChannels))
862                                                 next++;
863                                 }
864                                 if (IS_HT40_MODE(cm->mode) &&
865                                     (fband->lowChannel == 5280)) {
866                                         low_adj -= 20;
867                                 }
868                         }
869                 }
870         }
871 done:
872         if (next != 0) {
873                 int i;
874
875                 if (next > ARRAY_SIZE(ah->ah_channels)) {
876                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
877                                 "%s: too many channels %u; truncating to %u\n",
878                                 __func__, next,
879                                 (int) ARRAY_SIZE(ah->ah_channels));
880                         next = ARRAY_SIZE(ah->ah_channels);
881                 }
882 #ifdef ATH_NF_PER_CHAN
883                 ath9k_regd_init_rf_buffer(ichans, next);
884 #endif
885                 ath9k_regd_sort(ichans, next,
886                                 sizeof(struct ath9k_channel),
887                                 ath9k_regd_chansort);
888
889                 ah->ah_nchan = next;
890
891                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "Channel list:\n");
892                 for (i = 0; i < next; i++) {
893                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
894                                 "chan: %d flags: 0x%x\n",
895                                 ah->ah_channels[i].channel,
896                                 ah->ah_channels[i].channelFlags);
897                 }
898         }
899         *nchans = next;
900
901         ah->ah_countryCode = ah->ah_countryCode;
902
903         ah->ah_currentRDInUse = regdmn;
904         ah->ah_currentRD5G = rd5GHz.regDmnEnum;
905         ah->ah_currentRD2G = rd2GHz.regDmnEnum;
906         if (country == NULL) {
907                 ah->ah_iso[0] = 0;
908                 ah->ah_iso[1] = 0;
909         } else {
910                 ah->ah_iso[0] = country->isoName[0];
911                 ah->ah_iso[1] = country->isoName[1];
912         }
913
914         return next != 0;
915 }
916
917 struct ath9k_channel*
918 ath9k_regd_check_channel(struct ath_hal *ah,
919                          const struct ath9k_channel *c)
920 {
921         struct ath9k_channel *base, *cc;
922
923         int flags = c->channelFlags & CHAN_FLAGS;
924         int n, lim;
925
926         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
927                 "%s: channel %u/0x%x (0x%x) requested\n", __func__,
928                 c->channel, c->channelFlags, flags);
929
930         cc = ah->ah_curchan;
931         if (cc != NULL && cc->channel == c->channel &&
932             (cc->channelFlags & CHAN_FLAGS) == flags) {
933                 if ((cc->privFlags & CHANNEL_INTERFERENCE) &&
934                     (cc->privFlags & CHANNEL_DFS))
935                         return NULL;
936                 else
937                         return cc;
938         }
939
940         base = ah->ah_channels;
941         n = ah->ah_nchan;
942
943         for (lim = n; lim != 0; lim >>= 1) {
944                 int d;
945                 cc = &base[lim >> 1];
946                 d = c->channel - cc->channel;
947                 if (d == 0) {
948                         if ((cc->channelFlags & CHAN_FLAGS) == flags) {
949                                 if ((cc->privFlags & CHANNEL_INTERFERENCE) &&
950                                     (cc->privFlags & CHANNEL_DFS))
951                                         return NULL;
952                                 else
953                                         return cc;
954                         }
955                         d = flags - (cc->channelFlags & CHAN_FLAGS);
956                 }
957                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
958                         "%s: channel %u/0x%x d %d\n", __func__,
959                         cc->channel, cc->channelFlags, d);
960                 if (d > 0) {
961                         base = cc + 1;
962                         lim--;
963                 }
964         }
965         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: no match for %u/0x%x\n",
966                 __func__, c->channel, c->channelFlags);
967         return NULL;
968 }
969
970 u32
971 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
972                                struct ath9k_channel *chan)
973 {
974         struct ath9k_channel *ichan = NULL;
975
976         ichan = ath9k_regd_check_channel(ah, chan);
977         if (!ichan)
978                 return 0;
979
980         return ichan->antennaMax;
981 }
982
983 u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan)
984 {
985         u32 ctl = NO_CTL;
986         struct ath9k_channel *ichan;
987
988         if (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)) {
989                 if (IS_CHAN_B(chan))
990                         ctl = SD_NO_CTL | CTL_11B;
991                 else if (IS_CHAN_G(chan))
992                         ctl = SD_NO_CTL | CTL_11G;
993                 else
994                         ctl = SD_NO_CTL | CTL_11A;
995         } else {
996                 ichan = ath9k_regd_check_channel(ah, chan);
997                 if (ichan != NULL) {
998                         /* FIXME */
999                         if (IS_CHAN_A(ichan))
1000                                 ctl = ichan->conformanceTestLimit[0];
1001                         else if (IS_CHAN_B(ichan))
1002                                 ctl = ichan->conformanceTestLimit[1];
1003                         else if (IS_CHAN_G(ichan))
1004                                 ctl = ichan->conformanceTestLimit[2];
1005
1006                         if (IS_CHAN_G(chan) && (ctl & 0xf) == CTL_11B)
1007                                 ctl = (ctl & ~0xf) | CTL_11G;
1008                 }
1009         }
1010         return ctl;
1011 }
1012
1013 void ath9k_regd_get_current_country(struct ath_hal *ah,
1014                                     struct ath9k_country_entry *ctry)
1015 {
1016         u16 rd = ath9k_regd_get_eepromRD(ah);
1017
1018         ctry->isMultidomain = false;
1019         if (rd == CTRY_DEFAULT)
1020                 ctry->isMultidomain = true;
1021         else if (!(rd & COUNTRY_ERD_FLAG))
1022                 ctry->isMultidomain = isWwrSKU(ah);
1023
1024         ctry->countryCode = ah->ah_countryCode;
1025         ctry->regDmnEnum = ah->ah_currentRD;
1026         ctry->regDmn5G = ah->ah_currentRD5G;
1027         ctry->regDmn2G = ah->ah_currentRD2G;
1028         ctry->iso[0] = ah->ah_iso[0];
1029         ctry->iso[1] = ah->ah_iso[1];
1030         ctry->iso[2] = ah->ah_iso[2];
1031 }