Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[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.reg_cap;
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 void
135 ath9k_regd_get_wmodes_nreg(struct ath_hal *ah,
136                            struct country_code_to_enum_rd *country,
137                            struct regDomain *rd5GHz,
138                            unsigned long *modes_allowed)
139 {
140         bitmap_copy(modes_allowed, ah->ah_caps.wireless_modes, ATH9K_MODE_MAX);
141
142         if (test_bit(ATH9K_MODE_11G, ah->ah_caps.wireless_modes) &&
143             (!country->allow11g))
144                 clear_bit(ATH9K_MODE_11G, modes_allowed);
145
146         if (test_bit(ATH9K_MODE_11A, ah->ah_caps.wireless_modes) &&
147             (ath9k_regd_is_chan_bm_zero(rd5GHz->chan11a)))
148                 clear_bit(ATH9K_MODE_11A, modes_allowed);
149
150         if (test_bit(ATH9K_MODE_11NG_HT20, ah->ah_caps.wireless_modes)
151             && (!country->allow11ng20))
152                 clear_bit(ATH9K_MODE_11NG_HT20, modes_allowed);
153
154         if (test_bit(ATH9K_MODE_11NA_HT20, ah->ah_caps.wireless_modes)
155             && (!country->allow11na20))
156                 clear_bit(ATH9K_MODE_11NA_HT20, modes_allowed);
157
158         if (test_bit(ATH9K_MODE_11NG_HT40PLUS, ah->ah_caps.wireless_modes) &&
159             (!country->allow11ng40))
160                 clear_bit(ATH9K_MODE_11NG_HT40PLUS, modes_allowed);
161
162         if (test_bit(ATH9K_MODE_11NG_HT40MINUS, ah->ah_caps.wireless_modes) &&
163             (!country->allow11ng40))
164                 clear_bit(ATH9K_MODE_11NG_HT40MINUS, modes_allowed);
165
166         if (test_bit(ATH9K_MODE_11NA_HT40PLUS, ah->ah_caps.wireless_modes) &&
167             (!country->allow11na40))
168                 clear_bit(ATH9K_MODE_11NA_HT40PLUS, modes_allowed);
169
170         if (test_bit(ATH9K_MODE_11NA_HT40MINUS, ah->ah_caps.wireless_modes) &&
171             (!country->allow11na40))
172                 clear_bit(ATH9K_MODE_11NA_HT40MINUS, modes_allowed);
173 }
174
175 bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah)
176 {
177         u16 rd;
178
179         rd = ath9k_regd_get_eepromRD(ah);
180
181         switch (rd) {
182         case FCC4_FCCA:
183         case (CTRY_UNITED_STATES_FCC49 | COUNTRY_ERD_FLAG):
184                 return true;
185         case DEBUG_REG_DMN:
186         case NO_ENUMRD:
187                 if (ah->ah_countryCode == CTRY_UNITED_STATES_FCC49)
188                         return true;
189                 break;
190         }
191         return false;
192 }
193
194 static struct country_code_to_enum_rd*
195 ath9k_regd_find_country(u16 countryCode)
196 {
197         int i;
198
199         for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
200                 if (allCountries[i].countryCode == countryCode)
201                         return &allCountries[i];
202         }
203         return NULL;
204 }
205
206 static u16 ath9k_regd_get_default_country(struct ath_hal *ah)
207 {
208         u16 rd;
209         int i;
210
211         rd = ath9k_regd_get_eepromRD(ah);
212         if (rd & COUNTRY_ERD_FLAG) {
213                 struct country_code_to_enum_rd *country = NULL;
214                 u16 cc = rd & ~COUNTRY_ERD_FLAG;
215
216                 country = ath9k_regd_find_country(cc);
217                 if (country != NULL)
218                         return cc;
219         }
220
221         for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
222                 if (regDomainPairs[i].regDmnEnum == rd) {
223                         if (regDomainPairs[i].singleCC != 0)
224                                 return regDomainPairs[i].singleCC;
225                         else
226                                 i = ARRAY_SIZE(regDomainPairs);
227                 }
228         return CTRY_DEFAULT;
229 }
230
231 static bool ath9k_regd_is_valid_reg_domain(int regDmn,
232                                            struct regDomain *rd)
233 {
234         int i;
235
236         for (i = 0; i < ARRAY_SIZE(regDomains); i++) {
237                 if (regDomains[i].regDmnEnum == regDmn) {
238                         if (rd != NULL) {
239                                 memcpy(rd, &regDomains[i],
240                                        sizeof(struct regDomain));
241                         }
242                         return true;
243                 }
244         }
245         return false;
246 }
247
248 static bool ath9k_regd_is_valid_reg_domainPair(int regDmnPair)
249 {
250         int i;
251
252         if (regDmnPair == NO_ENUMRD)
253                 return false;
254         for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
255                 if (regDomainPairs[i].regDmnEnum == regDmnPair)
256                         return true;
257         }
258         return false;
259 }
260
261 static bool
262 ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn,
263                                u16 channelFlag, struct regDomain *rd)
264 {
265         int i, found;
266         u64 flags = NO_REQ;
267         struct reg_dmn_pair_mapping *regPair = NULL;
268         int regOrg;
269
270         regOrg = regDmn;
271         if (regDmn == CTRY_DEFAULT) {
272                 u16 rdnum;
273                 rdnum = ath9k_regd_get_eepromRD(ah);
274
275                 if (!(rdnum & COUNTRY_ERD_FLAG)) {
276                         if (ath9k_regd_is_valid_reg_domain(rdnum, NULL) ||
277                             ath9k_regd_is_valid_reg_domainPair(rdnum)) {
278                                 regDmn = rdnum;
279                         }
280                 }
281         }
282
283         if ((regDmn & MULTI_DOMAIN_MASK) == 0) {
284                 for (i = 0, found = 0;
285                      (i < ARRAY_SIZE(regDomainPairs)) && (!found); i++) {
286                         if (regDomainPairs[i].regDmnEnum == regDmn) {
287                                 regPair = &regDomainPairs[i];
288                                 found = 1;
289                         }
290                 }
291                 if (!found) {
292                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
293                                 "%s: Failed to find reg domain pair %u\n",
294                                 __func__, regDmn);
295                         return false;
296                 }
297                 if (!(channelFlag & CHANNEL_2GHZ)) {
298                         regDmn = regPair->regDmn5GHz;
299                         flags = regPair->flags5GHz;
300                 }
301                 if (channelFlag & CHANNEL_2GHZ) {
302                         regDmn = regPair->regDmn2GHz;
303                         flags = regPair->flags2GHz;
304                 }
305         }
306
307         found = ath9k_regd_is_valid_reg_domain(regDmn, rd);
308         if (!found) {
309                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
310                         "%s: Failed to find unitary reg domain %u\n",
311                         __func__, regDmn);
312                 return false;
313         } else {
314                 rd->pscan &= regPair->pscanMask;
315                 if (((regOrg & MULTI_DOMAIN_MASK) == 0) &&
316                     (flags != NO_REQ)) {
317                         rd->flags = flags;
318                 }
319
320                 rd->flags &= (channelFlag & CHANNEL_2GHZ) ?
321                     REG_DOMAIN_2GHZ_MASK : REG_DOMAIN_5GHZ_MASK;
322                 return true;
323         }
324 }
325
326 static bool ath9k_regd_is_bit_set(int bit, u64 *bitmask)
327 {
328         int byteOffset, bitnum;
329         u64 val;
330
331         byteOffset = bit / 64;
332         bitnum = bit - byteOffset * 64;
333         val = ((u64) 1) << bitnum;
334         if (bitmask[byteOffset] & val)
335                 return true;
336         else
337                 return false;
338 }
339
340 static void
341 ath9k_regd_add_reg_classid(u8 *regclassids, u32 maxregids,
342                            u32 *nregids, u8 regclassid)
343 {
344         int i;
345
346         if (regclassid == 0)
347                 return;
348
349         for (i = 0; i < maxregids; i++) {
350                 if (regclassids[i] == regclassid)
351                         return;
352                 if (regclassids[i] == 0)
353                         break;
354         }
355
356         if (i == maxregids)
357                 return;
358         else {
359                 regclassids[i] = regclassid;
360                 *nregids += 1;
361         }
362
363         return;
364 }
365
366 static bool
367 ath9k_regd_get_eeprom_reg_ext_bits(struct ath_hal *ah,
368                                    enum reg_ext_bitmap bit)
369 {
370         return (ah->ah_currentRDExt & (1 << bit)) ? true : false;
371 }
372
373 #ifdef ATH_NF_PER_CHAN
374
375 static void ath9k_regd_init_rf_buffer(struct ath9k_channel *ichans,
376                                       int nchans)
377 {
378         int i, j, next;
379
380         for (next = 0; next < nchans; next++) {
381                 for (i = 0; i < NUM_NF_READINGS; i++) {
382                         ichans[next].nfCalHist[i].currIndex = 0;
383                         ichans[next].nfCalHist[i].privNF =
384                             AR_PHY_CCA_MAX_GOOD_VALUE;
385                         ichans[next].nfCalHist[i].invalidNFcount =
386                             AR_PHY_CCA_FILTERWINDOW_LENGTH;
387                         for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
388                                 ichans[next].nfCalHist[i].nfCalBuffer[j] =
389                                     AR_PHY_CCA_MAX_GOOD_VALUE;
390                         }
391                 }
392         }
393 }
394 #endif
395
396 static int ath9k_regd_is_chan_present(struct ath_hal *ah,
397                                       u16 c)
398 {
399         int i;
400
401         for (i = 0; i < 150; i++) {
402                 if (!ah->ah_channels[i].channel)
403                         return -1;
404                 else if (ah->ah_channels[i].channel == c)
405                         return i;
406         }
407
408         return -1;
409 }
410
411 static bool
412 ath9k_regd_add_channel(struct ath_hal *ah,
413                        u16 c,
414                        u16 c_lo,
415                        u16 c_hi,
416                        u16 maxChan,
417                        u8 ctl,
418                        int pos,
419                        struct regDomain rd5GHz,
420                        struct RegDmnFreqBand *fband,
421                        struct regDomain *rd,
422                        const struct cmode *cm,
423                        struct ath9k_channel *ichans,
424                        bool enableExtendedChannels)
425 {
426         struct ath9k_channel *chan;
427         int ret;
428         u32 channelFlags = 0;
429         u8 privFlags = 0;
430
431         if (!(c_lo <= c && c <= c_hi)) {
432                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
433                         "%s: c %u out of range [%u..%u]\n",
434                         __func__, c, c_lo, c_hi);
435                 return false;
436         }
437         if ((fband->channelBW == CHANNEL_HALF_BW) &&
438             !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_HALFRATE)) {
439                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
440                         "%s: Skipping %u half rate channel\n",
441                         __func__, c);
442                 return false;
443         }
444
445         if ((fband->channelBW == CHANNEL_QUARTER_BW) &&
446             !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_QUARTERRATE)) {
447                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
448                         "%s: Skipping %u quarter rate channel\n",
449                         __func__, c);
450                 return false;
451         }
452
453         if (((c + fband->channelSep) / 2) > (maxChan + HALF_MAXCHANBW)) {
454                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
455                         "%s: c %u > maxChan %u\n",
456                         __func__, c, maxChan);
457                 return false;
458         }
459
460         if ((fband->usePassScan & IS_ECM_CHAN) && !enableExtendedChannels) {
461                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
462                         "Skipping ecm channel\n");
463                 return false;
464         }
465
466         if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == ATH9K_M_HOSTAP)) {
467                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
468                         "Skipping HOSTAP channel\n");
469                 return false;
470         }
471
472         if (IS_HT40_MODE(cm->mode) &&
473             !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_FCC_DFS_HT40)) &&
474             (fband->useDfs) &&
475             (rd->conformanceTestLimit != MKK)) {
476                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
477                         "Skipping HT40 channel (en_fcc_dfs_ht40 = 0)\n");
478                 return false;
479         }
480
481         if (IS_HT40_MODE(cm->mode) &&
482             !(ath9k_regd_get_eeprom_reg_ext_bits(ah,
483                                                  REG_EXT_JAPAN_NONDFS_HT40)) &&
484             !(fband->useDfs) && (rd->conformanceTestLimit == MKK)) {
485                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
486                         "Skipping HT40 channel (en_jap_ht40 = 0)\n");
487                 return false;
488         }
489
490         if (IS_HT40_MODE(cm->mode) &&
491             !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_JAPAN_DFS_HT40)) &&
492             (fband->useDfs) &&
493             (rd->conformanceTestLimit == MKK)) {
494                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
495                         "Skipping HT40 channel (en_jap_dfs_ht40 = 0)\n");
496                 return false;
497         }
498
499         /* Calculate channel flags */
500
501         channelFlags = cm->flags;
502
503         switch (fband->channelBW) {
504         case CHANNEL_HALF_BW:
505                 channelFlags |= CHANNEL_HALF;
506                 break;
507         case CHANNEL_QUARTER_BW:
508                 channelFlags |= CHANNEL_QUARTER;
509                 break;
510         }
511
512         if (fband->usePassScan & rd->pscan)
513                 channelFlags |= CHANNEL_PASSIVE;
514         else
515                 channelFlags &= ~CHANNEL_PASSIVE;
516         if (fband->useDfs & rd->dfsMask)
517                 privFlags = CHANNEL_DFS;
518         else
519                 privFlags = 0;
520         if (rd->flags & LIMIT_FRAME_4MS)
521                 privFlags |= CHANNEL_4MS_LIMIT;
522         if (privFlags & CHANNEL_DFS)
523                 privFlags |= CHANNEL_DISALLOW_ADHOC;
524         if (rd->flags & ADHOC_PER_11D)
525                 privFlags |= CHANNEL_PER_11D_ADHOC;
526
527         if (channelFlags & CHANNEL_PASSIVE) {
528                 if ((c < 2412) || (c > 2462)) {
529                         if (rd5GHz.regDmnEnum == MKK1 ||
530                             rd5GHz.regDmnEnum == MKK2) {
531                                 u32 regcap = ah->ah_caps.reg_cap;
532                                 if (!(regcap &
533                                       (AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
534                                        AR_EEPROM_EEREGCAP_EN_KK_U2 |
535                                        AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) &&
536                                     isUNII1OddChan(c)) {
537                                         channelFlags &= ~CHANNEL_PASSIVE;
538                                 } else {
539                                         privFlags |= CHANNEL_DISALLOW_ADHOC;
540                                 }
541                         } else {
542                                 privFlags |= CHANNEL_DISALLOW_ADHOC;
543                         }
544                 }
545         }
546
547         if ((cm->mode == ATH9K_MODE_11A) ||
548             (cm->mode == ATH9K_MODE_11NA_HT20) ||
549             (cm->mode == ATH9K_MODE_11NA_HT40PLUS) ||
550             (cm->mode == ATH9K_MODE_11NA_HT40MINUS)) {
551                 if (rd->flags & (ADHOC_NO_11A | DISALLOW_ADHOC_11A))
552                         privFlags |= CHANNEL_DISALLOW_ADHOC;
553         }
554
555         /* Fill in channel details */
556
557         ret = ath9k_regd_is_chan_present(ah, c);
558         if (ret == -1) {
559                 chan = &ah->ah_channels[pos];
560                 chan->channel = c;
561                 chan->maxRegTxPower = fband->powerDfs;
562                 chan->antennaMax = fband->antennaMax;
563                 chan->regDmnFlags = rd->flags;
564                 chan->maxTxPower = AR5416_MAX_RATE_POWER;
565                 chan->minTxPower = AR5416_MAX_RATE_POWER;
566                 chan->channelFlags = channelFlags;
567                 chan->privFlags = privFlags;
568         } else {
569                 chan = &ah->ah_channels[ret];
570                 chan->channelFlags |= channelFlags;
571                 chan->privFlags |= privFlags;
572         }
573
574         /* Set CTLs */
575
576         if ((cm->flags & CHANNEL_ALL) == CHANNEL_A)
577                 chan->conformanceTestLimit[0] = ctl;
578         else if ((cm->flags & CHANNEL_ALL) == CHANNEL_B)
579                 chan->conformanceTestLimit[1] = ctl;
580         else if ((cm->flags & CHANNEL_ALL) == CHANNEL_G)
581                 chan->conformanceTestLimit[2] = ctl;
582
583         return (ret == -1) ? true : false;
584 }
585
586 static bool ath9k_regd_japan_check(struct ath_hal *ah,
587                                    int b,
588                                    struct regDomain *rd5GHz)
589 {
590         bool skipband = false;
591         int i;
592         u32 regcap;
593
594         for (i = 0; i < ARRAY_SIZE(j_bandcheck); i++) {
595                 if (j_bandcheck[i].freqbandbit == b) {
596                         regcap = ah->ah_caps.reg_cap;
597                         if ((j_bandcheck[i].eepromflagtocheck & regcap) == 0) {
598                                 skipband = true;
599                         } else if ((regcap & AR_EEPROM_EEREGCAP_EN_KK_U2) ||
600                                   (regcap & AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) {
601                                 rd5GHz->dfsMask |= DFS_MKK4;
602                                 rd5GHz->pscan |= PSCAN_MKK3;
603                         }
604                         break;
605                 }
606         }
607
608         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
609                 "%s: Skipping %d freq band\n",
610                 __func__, j_bandcheck[i].freqbandbit);
611
612         return skipband;
613 }
614
615 bool
616 ath9k_regd_init_channels(struct ath_hal *ah,
617                          u32 maxchans,
618                          u32 *nchans, u8 *regclassids,
619                          u32 maxregids, u32 *nregids, u16 cc,
620                          bool enableOutdoor,
621                          bool enableExtendedChannels)
622 {
623         u16 maxChan = 7000;
624         struct country_code_to_enum_rd *country = NULL;
625         struct regDomain rd5GHz, rd2GHz;
626         const struct cmode *cm;
627         struct ath9k_channel *ichans = &ah->ah_channels[0];
628         int next = 0, b;
629         u8 ctl;
630         int regdmn;
631         u16 chanSep;
632         unsigned long *modes_avail;
633         DECLARE_BITMAP(modes_allowed, ATH9K_MODE_MAX);
634
635         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: cc %u %s %s\n",
636                  __func__, cc,
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                 modes_avail = ah->ah_caps.wireless_modes;
730         } else {
731                 ath9k_regd_get_wmodes_nreg(ah, country, &rd5GHz, modes_allowed);
732                 modes_avail = modes_allowed;
733
734                 if (!enableOutdoor)
735                         maxChan = country->outdoorChanStart;
736         }
737
738         next = 0;
739
740         if (maxchans > ARRAY_SIZE(ah->ah_channels))
741                 maxchans = ARRAY_SIZE(ah->ah_channels);
742
743         for (cm = modes; cm < &modes[ARRAY_SIZE(modes)]; cm++) {
744                 u16 c, c_hi, c_lo;
745                 u64 *channelBM = NULL;
746                 struct regDomain *rd = NULL;
747                 struct RegDmnFreqBand *fband = NULL, *freqs;
748                 int8_t low_adj = 0, hi_adj = 0;
749
750                 if (!test_bit(cm->mode, modes_avail)) {
751                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
752                                 "%s: !avail mode %d flags 0x%x\n",
753                                 __func__, cm->mode, cm->flags);
754                         continue;
755                 }
756                 if (!ath9k_get_channel_edges(ah, cm->flags, &c_lo, &c_hi)) {
757                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
758                                 "%s: channels 0x%x not supported "
759                                 "by hardware\n",
760                                 __func__, cm->flags);
761                         continue;
762                 }
763
764                 switch (cm->mode) {
765                 case ATH9K_MODE_11A:
766                 case ATH9K_MODE_11NA_HT20:
767                 case ATH9K_MODE_11NA_HT40PLUS:
768                 case ATH9K_MODE_11NA_HT40MINUS:
769                         rd = &rd5GHz;
770                         channelBM = rd->chan11a;
771                         freqs = &regDmn5GhzFreq[0];
772                         ctl = rd->conformanceTestLimit;
773                         break;
774                 case ATH9K_MODE_11B:
775                         rd = &rd2GHz;
776                         channelBM = rd->chan11b;
777                         freqs = &regDmn2GhzFreq[0];
778                         ctl = rd->conformanceTestLimit | CTL_11B;
779                         break;
780                 case ATH9K_MODE_11G:
781                 case ATH9K_MODE_11NG_HT20:
782                 case ATH9K_MODE_11NG_HT40PLUS:
783                 case ATH9K_MODE_11NG_HT40MINUS:
784                         rd = &rd2GHz;
785                         channelBM = rd->chan11g;
786                         freqs = &regDmn2Ghz11gFreq[0];
787                         ctl = rd->conformanceTestLimit | CTL_11G;
788                         break;
789                 default:
790                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
791                                 "%s: Unknown HAL mode 0x%x\n", __func__,
792                                 cm->mode);
793                         continue;
794                 }
795
796                 if (ath9k_regd_is_chan_bm_zero(channelBM))
797                         continue;
798
799                 if ((cm->mode == ATH9K_MODE_11NA_HT40PLUS) ||
800                     (cm->mode == ATH9K_MODE_11NG_HT40PLUS)) {
801                         hi_adj = -20;
802                 }
803
804                 if ((cm->mode == ATH9K_MODE_11NA_HT40MINUS) ||
805                     (cm->mode == ATH9K_MODE_11NG_HT40MINUS)) {
806                         low_adj = 20;
807                 }
808
809                 /* XXX: Add a helper here instead */
810                 for (b = 0; b < 64 * BMLEN; b++) {
811                         if (ath9k_regd_is_bit_set(b, channelBM)) {
812                                 fband = &freqs[b];
813                                 if (rd5GHz.regDmnEnum == MKK1
814                                     || rd5GHz.regDmnEnum == MKK2) {
815                                         if (ath9k_regd_japan_check(ah,
816                                                                    b,
817                                                                    &rd5GHz))
818                                                 continue;
819                                 }
820
821                                 ath9k_regd_add_reg_classid(regclassids,
822                                                            maxregids,
823                                                            nregids,
824                                                            fband->
825                                                            regClassId);
826
827                                 if (IS_HT40_MODE(cm->mode) && (rd == &rd5GHz)) {
828                                         chanSep = 40;
829                                         if (fband->lowChannel == 5280)
830                                                 low_adj += 20;
831
832                                         if (fband->lowChannel == 5170)
833                                                 continue;
834                                 } else
835                                         chanSep = fband->channelSep;
836
837                                 for (c = fband->lowChannel + low_adj;
838                                      ((c <= (fband->highChannel + hi_adj)) &&
839                                       (c >= (fband->lowChannel + low_adj)));
840                                      c += chanSep) {
841                                         if (next >= maxchans) {
842                                                 DPRINTF(ah->ah_sc,
843                                                         ATH_DBG_REGULATORY,
844                                                         "%s: too many channels "
845                                                         "for channel table\n",
846                                                         __func__);
847                                                 goto done;
848                                         }
849                                         if (ath9k_regd_add_channel(ah,
850                                                    c, c_lo, c_hi,
851                                                    maxChan, ctl,
852                                                    next,
853                                                    rd5GHz,
854                                                    fband, rd, cm,
855                                                    ichans,
856                                                    enableExtendedChannels))
857                                                 next++;
858                                 }
859                                 if (IS_HT40_MODE(cm->mode) &&
860                                     (fband->lowChannel == 5280)) {
861                                         low_adj -= 20;
862                                 }
863                         }
864                 }
865         }
866 done:
867         if (next != 0) {
868                 int i;
869
870                 if (next > ARRAY_SIZE(ah->ah_channels)) {
871                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
872                                 "%s: too many channels %u; truncating to %u\n",
873                                 __func__, next,
874                                 (int) ARRAY_SIZE(ah->ah_channels));
875                         next = ARRAY_SIZE(ah->ah_channels);
876                 }
877 #ifdef ATH_NF_PER_CHAN
878                 ath9k_regd_init_rf_buffer(ichans, next);
879 #endif
880                 ath9k_regd_sort(ichans, next,
881                                 sizeof(struct ath9k_channel),
882                                 ath9k_regd_chansort);
883
884                 ah->ah_nchan = next;
885
886                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "Channel list:\n");
887                 for (i = 0; i < next; i++) {
888                         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
889                                 "chan: %d flags: 0x%x\n",
890                                 ah->ah_channels[i].channel,
891                                 ah->ah_channels[i].channelFlags);
892                 }
893         }
894         *nchans = next;
895
896         ah->ah_countryCode = ah->ah_countryCode;
897
898         ah->ah_currentRDInUse = regdmn;
899         ah->ah_currentRD5G = rd5GHz.regDmnEnum;
900         ah->ah_currentRD2G = rd2GHz.regDmnEnum;
901         if (country == NULL) {
902                 ah->ah_iso[0] = 0;
903                 ah->ah_iso[1] = 0;
904         } else {
905                 ah->ah_iso[0] = country->isoName[0];
906                 ah->ah_iso[1] = country->isoName[1];
907         }
908
909         return next != 0;
910 }
911
912 struct ath9k_channel*
913 ath9k_regd_check_channel(struct ath_hal *ah,
914                          const struct ath9k_channel *c)
915 {
916         struct ath9k_channel *base, *cc;
917
918         int flags = c->channelFlags & CHAN_FLAGS;
919         int n, lim;
920
921         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
922                 "%s: channel %u/0x%x (0x%x) requested\n", __func__,
923                 c->channel, c->channelFlags, flags);
924
925         cc = ah->ah_curchan;
926         if (cc != NULL && cc->channel == c->channel &&
927             (cc->channelFlags & CHAN_FLAGS) == flags) {
928                 if ((cc->privFlags & CHANNEL_INTERFERENCE) &&
929                     (cc->privFlags & CHANNEL_DFS))
930                         return NULL;
931                 else
932                         return cc;
933         }
934
935         base = ah->ah_channels;
936         n = ah->ah_nchan;
937
938         for (lim = n; lim != 0; lim >>= 1) {
939                 int d;
940                 cc = &base[lim >> 1];
941                 d = c->channel - cc->channel;
942                 if (d == 0) {
943                         if ((cc->channelFlags & CHAN_FLAGS) == flags) {
944                                 if ((cc->privFlags & CHANNEL_INTERFERENCE) &&
945                                     (cc->privFlags & CHANNEL_DFS))
946                                         return NULL;
947                                 else
948                                         return cc;
949                         }
950                         d = flags - (cc->channelFlags & CHAN_FLAGS);
951                 }
952                 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
953                         "%s: channel %u/0x%x d %d\n", __func__,
954                         cc->channel, cc->channelFlags, d);
955                 if (d > 0) {
956                         base = cc + 1;
957                         lim--;
958                 }
959         }
960         DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: no match for %u/0x%x\n",
961                 __func__, c->channel, c->channelFlags);
962         return NULL;
963 }
964
965 u32
966 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
967                                struct ath9k_channel *chan)
968 {
969         struct ath9k_channel *ichan = NULL;
970
971         ichan = ath9k_regd_check_channel(ah, chan);
972         if (!ichan)
973                 return 0;
974
975         return ichan->antennaMax;
976 }
977
978 u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan)
979 {
980         u32 ctl = NO_CTL;
981         struct ath9k_channel *ichan;
982
983         if (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)) {
984                 if (IS_CHAN_B(chan))
985                         ctl = SD_NO_CTL | CTL_11B;
986                 else if (IS_CHAN_G(chan))
987                         ctl = SD_NO_CTL | CTL_11G;
988                 else
989                         ctl = SD_NO_CTL | CTL_11A;
990         } else {
991                 ichan = ath9k_regd_check_channel(ah, chan);
992                 if (ichan != NULL) {
993                         /* FIXME */
994                         if (IS_CHAN_A(ichan))
995                                 ctl = ichan->conformanceTestLimit[0];
996                         else if (IS_CHAN_B(ichan))
997                                 ctl = ichan->conformanceTestLimit[1];
998                         else if (IS_CHAN_G(ichan))
999                                 ctl = ichan->conformanceTestLimit[2];
1000
1001                         if (IS_CHAN_G(chan) && (ctl & 0xf) == CTL_11B)
1002                                 ctl = (ctl & ~0xf) | CTL_11G;
1003                 }
1004         }
1005         return ctl;
1006 }
1007
1008 void ath9k_regd_get_current_country(struct ath_hal *ah,
1009                                     struct ath9k_country_entry *ctry)
1010 {
1011         u16 rd = ath9k_regd_get_eepromRD(ah);
1012
1013         ctry->isMultidomain = false;
1014         if (rd == CTRY_DEFAULT)
1015                 ctry->isMultidomain = true;
1016         else if (!(rd & COUNTRY_ERD_FLAG))
1017                 ctry->isMultidomain = isWwrSKU(ah);
1018
1019         ctry->countryCode = ah->ah_countryCode;
1020         ctry->regDmnEnum = ah->ah_currentRD;
1021         ctry->regDmn5G = ah->ah_currentRD5G;
1022         ctry->regDmn2G = ah->ah_currentRD2G;
1023         ctry->iso[0] = ah->ah_iso[0];
1024         ctry->iso[1] = ah->ah_iso[1];
1025         ctry->iso[2] = ah->ah_iso[2];
1026 }