2 * Copyright (c) 2008 Atheros Communications Inc.
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.
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.
17 #include <linux/kernel.h>
18 #include <linux/slab.h>
22 #include "regd_common.h"
24 static int ath9k_regd_chansort(const void *a
, const void *b
)
26 const struct ath9k_channel
*ca
= a
;
27 const struct ath9k_channel
*cb
= b
;
29 return (ca
->channel
== cb
->channel
) ?
30 (ca
->channelFlags
& CHAN_FLAGS
) -
31 (cb
->channelFlags
& CHAN_FLAGS
) : ca
->channel
- cb
->channel
;
35 ath9k_regd_sort(void *a
, u32 n
, u32 size
, ath_hal_cmp_t
*cmp
)
40 for (ai
= aa
+ size
; --n
>= 1; ai
+= size
)
41 for (t
= ai
; t
> aa
; t
-= size
) {
49 static u16
ath9k_regd_get_eepromRD(struct ath_hal
*ah
)
51 return ah
->ah_currentRD
& ~WORLDWIDE_ROAMING_FLAG
;
54 static bool ath9k_regd_is_chan_bm_zero(u64
*bitmask
)
58 for (i
= 0; i
< BMLEN
; i
++) {
65 static bool ath9k_regd_is_eeprom_valid(struct ath_hal
*ah
)
67 u16 rd
= ath9k_regd_get_eepromRD(ah
);
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
)
76 for (i
= 0; i
< ARRAY_SIZE(regDomainPairs
); i
++)
77 if (regDomainPairs
[i
].regDmnEnum
== rd
)
80 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
81 "invalid regulatory domain/country code 0x%x\n", rd
);
85 static bool ath9k_regd_is_fcc_midband_supported(struct ath_hal
*ah
)
89 regcap
= ah
->ah_caps
.reg_cap
;
91 if (regcap
& AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND
)
97 static bool ath9k_regd_is_ccode_valid(struct ath_hal
*ah
,
103 if (cc
== CTRY_DEFAULT
)
105 if (cc
== CTRY_DEBUG
)
108 rd
= ath9k_regd_get_eepromRD(ah
);
109 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
, "EEPROM regdomain 0x%x\n", rd
);
111 if (rd
& COUNTRY_ERD_FLAG
) {
112 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
113 "EEPROM setting is country code %u\n",
114 rd
& ~COUNTRY_ERD_FLAG
);
115 return cc
== (rd
& ~COUNTRY_ERD_FLAG
);
118 for (i
= 0; i
< ARRAY_SIZE(allCountries
); i
++) {
119 if (cc
== allCountries
[i
].countryCode
) {
120 #ifdef AH_SUPPORT_11D
121 if ((rd
& WORLD_SKU_MASK
) == WORLD_SKU_PREFIX
)
124 if (allCountries
[i
].regDmnEnum
== rd
||
125 rd
== DEBUG_REG_DMN
|| rd
== NO_ENUMRD
)
133 ath9k_regd_get_wmodes_nreg(struct ath_hal
*ah
,
134 struct country_code_to_enum_rd
*country
,
135 struct regDomain
*rd5GHz
,
136 unsigned long *modes_allowed
)
138 bitmap_copy(modes_allowed
, ah
->ah_caps
.wireless_modes
, ATH9K_MODE_MAX
);
140 if (test_bit(ATH9K_MODE_11G
, ah
->ah_caps
.wireless_modes
) &&
141 (!country
->allow11g
))
142 clear_bit(ATH9K_MODE_11G
, modes_allowed
);
144 if (test_bit(ATH9K_MODE_11A
, ah
->ah_caps
.wireless_modes
) &&
145 (ath9k_regd_is_chan_bm_zero(rd5GHz
->chan11a
)))
146 clear_bit(ATH9K_MODE_11A
, modes_allowed
);
148 if (test_bit(ATH9K_MODE_11NG_HT20
, ah
->ah_caps
.wireless_modes
)
149 && (!country
->allow11ng20
))
150 clear_bit(ATH9K_MODE_11NG_HT20
, modes_allowed
);
152 if (test_bit(ATH9K_MODE_11NA_HT20
, ah
->ah_caps
.wireless_modes
)
153 && (!country
->allow11na20
))
154 clear_bit(ATH9K_MODE_11NA_HT20
, modes_allowed
);
156 if (test_bit(ATH9K_MODE_11NG_HT40PLUS
, ah
->ah_caps
.wireless_modes
) &&
157 (!country
->allow11ng40
))
158 clear_bit(ATH9K_MODE_11NG_HT40PLUS
, modes_allowed
);
160 if (test_bit(ATH9K_MODE_11NG_HT40MINUS
, ah
->ah_caps
.wireless_modes
) &&
161 (!country
->allow11ng40
))
162 clear_bit(ATH9K_MODE_11NG_HT40MINUS
, modes_allowed
);
164 if (test_bit(ATH9K_MODE_11NA_HT40PLUS
, ah
->ah_caps
.wireless_modes
) &&
165 (!country
->allow11na40
))
166 clear_bit(ATH9K_MODE_11NA_HT40PLUS
, modes_allowed
);
168 if (test_bit(ATH9K_MODE_11NA_HT40MINUS
, ah
->ah_caps
.wireless_modes
) &&
169 (!country
->allow11na40
))
170 clear_bit(ATH9K_MODE_11NA_HT40MINUS
, modes_allowed
);
173 bool ath9k_regd_is_public_safety_sku(struct ath_hal
*ah
)
177 rd
= ath9k_regd_get_eepromRD(ah
);
181 case (CTRY_UNITED_STATES_FCC49
| COUNTRY_ERD_FLAG
):
185 if (ah
->ah_countryCode
== CTRY_UNITED_STATES_FCC49
)
192 static struct country_code_to_enum_rd
*
193 ath9k_regd_find_country(u16 countryCode
)
197 for (i
= 0; i
< ARRAY_SIZE(allCountries
); i
++) {
198 if (allCountries
[i
].countryCode
== countryCode
)
199 return &allCountries
[i
];
204 static u16
ath9k_regd_get_default_country(struct ath_hal
*ah
)
209 rd
= ath9k_regd_get_eepromRD(ah
);
210 if (rd
& COUNTRY_ERD_FLAG
) {
211 struct country_code_to_enum_rd
*country
= NULL
;
212 u16 cc
= rd
& ~COUNTRY_ERD_FLAG
;
214 country
= ath9k_regd_find_country(cc
);
219 for (i
= 0; i
< ARRAY_SIZE(regDomainPairs
); i
++)
220 if (regDomainPairs
[i
].regDmnEnum
== rd
) {
221 if (regDomainPairs
[i
].singleCC
!= 0)
222 return regDomainPairs
[i
].singleCC
;
224 i
= ARRAY_SIZE(regDomainPairs
);
229 static bool ath9k_regd_is_valid_reg_domain(int regDmn
,
230 struct regDomain
*rd
)
234 for (i
= 0; i
< ARRAY_SIZE(regDomains
); i
++) {
235 if (regDomains
[i
].regDmnEnum
== regDmn
) {
237 memcpy(rd
, ®Domains
[i
],
238 sizeof(struct regDomain
));
246 static bool ath9k_regd_is_valid_reg_domainPair(int regDmnPair
)
250 if (regDmnPair
== NO_ENUMRD
)
252 for (i
= 0; i
< ARRAY_SIZE(regDomainPairs
); i
++) {
253 if (regDomainPairs
[i
].regDmnEnum
== regDmnPair
)
260 ath9k_regd_get_wmode_regdomain(struct ath_hal
*ah
, int regDmn
,
261 u16 channelFlag
, struct regDomain
*rd
)
265 struct reg_dmn_pair_mapping
*regPair
= NULL
;
269 if (regDmn
== CTRY_DEFAULT
) {
271 rdnum
= ath9k_regd_get_eepromRD(ah
);
273 if (!(rdnum
& COUNTRY_ERD_FLAG
)) {
274 if (ath9k_regd_is_valid_reg_domain(rdnum
, NULL
) ||
275 ath9k_regd_is_valid_reg_domainPair(rdnum
)) {
281 if ((regDmn
& MULTI_DOMAIN_MASK
) == 0) {
282 for (i
= 0, found
= 0;
283 (i
< ARRAY_SIZE(regDomainPairs
)) && (!found
); i
++) {
284 if (regDomainPairs
[i
].regDmnEnum
== regDmn
) {
285 regPair
= ®DomainPairs
[i
];
290 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
291 "Failed to find reg domain pair %u\n", regDmn
);
294 if (!(channelFlag
& CHANNEL_2GHZ
)) {
295 regDmn
= regPair
->regDmn5GHz
;
296 flags
= regPair
->flags5GHz
;
298 if (channelFlag
& CHANNEL_2GHZ
) {
299 regDmn
= regPair
->regDmn2GHz
;
300 flags
= regPair
->flags2GHz
;
304 found
= ath9k_regd_is_valid_reg_domain(regDmn
, rd
);
306 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
307 "Failed to find unitary reg domain %u\n", regDmn
);
310 rd
->pscan
&= regPair
->pscanMask
;
311 if (((regOrg
& MULTI_DOMAIN_MASK
) == 0) &&
316 rd
->flags
&= (channelFlag
& CHANNEL_2GHZ
) ?
317 REG_DOMAIN_2GHZ_MASK
: REG_DOMAIN_5GHZ_MASK
;
322 static bool ath9k_regd_is_bit_set(int bit
, u64
*bitmask
)
324 int byteOffset
, bitnum
;
327 byteOffset
= bit
/ 64;
328 bitnum
= bit
- byteOffset
* 64;
329 val
= ((u64
) 1) << bitnum
;
330 if (bitmask
[byteOffset
] & val
)
337 ath9k_regd_add_reg_classid(u8
*regclassids
, u32 maxregids
,
338 u32
*nregids
, u8 regclassid
)
345 for (i
= 0; i
< maxregids
; i
++) {
346 if (regclassids
[i
] == regclassid
)
348 if (regclassids
[i
] == 0)
355 regclassids
[i
] = regclassid
;
363 ath9k_regd_get_eeprom_reg_ext_bits(struct ath_hal
*ah
,
364 enum reg_ext_bitmap bit
)
366 return (ah
->ah_currentRDExt
& (1 << bit
)) ? true : false;
369 #ifdef ATH_NF_PER_CHAN
371 static void ath9k_regd_init_rf_buffer(struct ath9k_channel
*ichans
,
376 for (next
= 0; next
< nchans
; next
++) {
377 for (i
= 0; i
< NUM_NF_READINGS
; i
++) {
378 ichans
[next
].nfCalHist
[i
].currIndex
= 0;
379 ichans
[next
].nfCalHist
[i
].privNF
=
380 AR_PHY_CCA_MAX_GOOD_VALUE
;
381 ichans
[next
].nfCalHist
[i
].invalidNFcount
=
382 AR_PHY_CCA_FILTERWINDOW_LENGTH
;
383 for (j
= 0; j
< ATH9K_NF_CAL_HIST_MAX
; j
++) {
384 ichans
[next
].nfCalHist
[i
].nfCalBuffer
[j
] =
385 AR_PHY_CCA_MAX_GOOD_VALUE
;
392 static int ath9k_regd_is_chan_present(struct ath_hal
*ah
,
397 for (i
= 0; i
< 150; i
++) {
398 if (!ah
->ah_channels
[i
].channel
)
400 else if (ah
->ah_channels
[i
].channel
== c
)
408 ath9k_regd_add_channel(struct ath_hal
*ah
,
415 struct regDomain rd5GHz
,
416 struct RegDmnFreqBand
*fband
,
417 struct regDomain
*rd
,
418 const struct cmode
*cm
,
419 struct ath9k_channel
*ichans
,
420 bool enableExtendedChannels
)
422 struct ath9k_channel
*chan
;
424 u32 channelFlags
= 0;
427 if (!(c_lo
<= c
&& c
<= c_hi
)) {
428 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
429 "c %u out of range [%u..%u]\n",
433 if ((fband
->channelBW
== CHANNEL_HALF_BW
) &&
434 !(ah
->ah_caps
.hw_caps
& ATH9K_HW_CAP_CHAN_HALFRATE
)) {
435 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
436 "Skipping %u half rate channel\n", c
);
440 if ((fband
->channelBW
== CHANNEL_QUARTER_BW
) &&
441 !(ah
->ah_caps
.hw_caps
& ATH9K_HW_CAP_CHAN_QUARTERRATE
)) {
442 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
443 "Skipping %u quarter rate channel\n", c
);
447 if (((c
+ fband
->channelSep
) / 2) > (maxChan
+ HALF_MAXCHANBW
)) {
448 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
449 "c %u > maxChan %u\n", c
, maxChan
);
453 if ((fband
->usePassScan
& IS_ECM_CHAN
) && !enableExtendedChannels
) {
454 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
455 "Skipping ecm channel\n");
459 if ((rd
->flags
& NO_HOSTAP
) && (ah
->ah_opmode
== NL80211_IFTYPE_AP
)) {
460 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
461 "Skipping HOSTAP channel\n");
465 if (IS_HT40_MODE(cm
->mode
) &&
466 !(ath9k_regd_get_eeprom_reg_ext_bits(ah
, REG_EXT_FCC_DFS_HT40
)) &&
468 (rd
->conformanceTestLimit
!= MKK
)) {
469 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
470 "Skipping HT40 channel (en_fcc_dfs_ht40 = 0)\n");
474 if (IS_HT40_MODE(cm
->mode
) &&
475 !(ath9k_regd_get_eeprom_reg_ext_bits(ah
,
476 REG_EXT_JAPAN_NONDFS_HT40
)) &&
477 !(fband
->useDfs
) && (rd
->conformanceTestLimit
== MKK
)) {
478 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
479 "Skipping HT40 channel (en_jap_ht40 = 0)\n");
483 if (IS_HT40_MODE(cm
->mode
) &&
484 !(ath9k_regd_get_eeprom_reg_ext_bits(ah
, REG_EXT_JAPAN_DFS_HT40
)) &&
486 (rd
->conformanceTestLimit
== MKK
)) {
487 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
488 "Skipping HT40 channel (en_jap_dfs_ht40 = 0)\n");
492 /* Calculate channel flags */
494 channelFlags
= cm
->flags
;
496 switch (fband
->channelBW
) {
497 case CHANNEL_HALF_BW
:
498 channelFlags
|= CHANNEL_HALF
;
500 case CHANNEL_QUARTER_BW
:
501 channelFlags
|= CHANNEL_QUARTER
;
505 if (fband
->usePassScan
& rd
->pscan
)
506 channelFlags
|= CHANNEL_PASSIVE
;
508 channelFlags
&= ~CHANNEL_PASSIVE
;
509 if (fband
->useDfs
& rd
->dfsMask
)
510 privFlags
= CHANNEL_DFS
;
513 if (rd
->flags
& LIMIT_FRAME_4MS
)
514 privFlags
|= CHANNEL_4MS_LIMIT
;
515 if (privFlags
& CHANNEL_DFS
)
516 privFlags
|= CHANNEL_DISALLOW_ADHOC
;
517 if (rd
->flags
& ADHOC_PER_11D
)
518 privFlags
|= CHANNEL_PER_11D_ADHOC
;
520 if (channelFlags
& CHANNEL_PASSIVE
) {
521 if ((c
< 2412) || (c
> 2462)) {
522 if (rd5GHz
.regDmnEnum
== MKK1
||
523 rd5GHz
.regDmnEnum
== MKK2
) {
524 u32 regcap
= ah
->ah_caps
.reg_cap
;
526 (AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN
|
527 AR_EEPROM_EEREGCAP_EN_KK_U2
|
528 AR_EEPROM_EEREGCAP_EN_KK_MIDBAND
)) &&
530 channelFlags
&= ~CHANNEL_PASSIVE
;
532 privFlags
|= CHANNEL_DISALLOW_ADHOC
;
535 privFlags
|= CHANNEL_DISALLOW_ADHOC
;
540 if ((cm
->mode
== ATH9K_MODE_11A
) ||
541 (cm
->mode
== ATH9K_MODE_11NA_HT20
) ||
542 (cm
->mode
== ATH9K_MODE_11NA_HT40PLUS
) ||
543 (cm
->mode
== ATH9K_MODE_11NA_HT40MINUS
)) {
544 if (rd
->flags
& (ADHOC_NO_11A
| DISALLOW_ADHOC_11A
))
545 privFlags
|= CHANNEL_DISALLOW_ADHOC
;
548 /* Fill in channel details */
550 ret
= ath9k_regd_is_chan_present(ah
, c
);
552 chan
= &ah
->ah_channels
[pos
];
554 chan
->maxRegTxPower
= fband
->powerDfs
;
555 chan
->antennaMax
= fband
->antennaMax
;
556 chan
->regDmnFlags
= rd
->flags
;
557 chan
->maxTxPower
= AR5416_MAX_RATE_POWER
;
558 chan
->minTxPower
= AR5416_MAX_RATE_POWER
;
559 chan
->channelFlags
= channelFlags
;
560 chan
->privFlags
= privFlags
;
562 chan
= &ah
->ah_channels
[ret
];
563 chan
->channelFlags
|= channelFlags
;
564 chan
->privFlags
|= privFlags
;
569 if ((cm
->flags
& CHANNEL_ALL
) == CHANNEL_A
)
570 chan
->conformanceTestLimit
[0] = ctl
;
571 else if ((cm
->flags
& CHANNEL_ALL
) == CHANNEL_B
)
572 chan
->conformanceTestLimit
[1] = ctl
;
573 else if ((cm
->flags
& CHANNEL_ALL
) == CHANNEL_G
)
574 chan
->conformanceTestLimit
[2] = ctl
;
576 return (ret
== -1) ? true : false;
579 static bool ath9k_regd_japan_check(struct ath_hal
*ah
,
581 struct regDomain
*rd5GHz
)
583 bool skipband
= false;
587 for (i
= 0; i
< ARRAY_SIZE(j_bandcheck
); i
++) {
588 if (j_bandcheck
[i
].freqbandbit
== b
) {
589 regcap
= ah
->ah_caps
.reg_cap
;
590 if ((j_bandcheck
[i
].eepromflagtocheck
& regcap
) == 0) {
592 } else if ((regcap
& AR_EEPROM_EEREGCAP_EN_KK_U2
) ||
593 (regcap
& AR_EEPROM_EEREGCAP_EN_KK_MIDBAND
)) {
594 rd5GHz
->dfsMask
|= DFS_MKK4
;
595 rd5GHz
->pscan
|= PSCAN_MKK3
;
601 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
602 "Skipping %d freq band\n", j_bandcheck
[i
].freqbandbit
);
608 ath9k_regd_init_channels(struct ath_hal
*ah
,
610 u32
*nchans
, u8
*regclassids
,
611 u32 maxregids
, u32
*nregids
, u16 cc
,
613 bool enableExtendedChannels
)
616 struct country_code_to_enum_rd
*country
= NULL
;
617 struct regDomain rd5GHz
, rd2GHz
;
618 const struct cmode
*cm
;
619 struct ath9k_channel
*ichans
= &ah
->ah_channels
[0];
624 unsigned long *modes_avail
;
625 DECLARE_BITMAP(modes_allowed
, ATH9K_MODE_MAX
);
627 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
, "cc %u %s %s\n", cc
,
628 enableOutdoor
? "Enable outdoor" : "",
629 enableExtendedChannels
? "Enable ecm" : "");
631 if (!ath9k_regd_is_ccode_valid(ah
, cc
)) {
632 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
633 "Invalid country code %d\n", cc
);
637 if (!ath9k_regd_is_eeprom_valid(ah
)) {
638 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
639 "Invalid EEPROM contents\n");
643 ah
->ah_countryCode
= ath9k_regd_get_default_country(ah
);
645 if (ah
->ah_countryCode
== CTRY_DEFAULT
) {
646 ah
->ah_countryCode
= cc
& COUNTRY_CODE_MASK
;
647 if ((ah
->ah_countryCode
== CTRY_DEFAULT
) &&
648 (ath9k_regd_get_eepromRD(ah
) == CTRY_DEFAULT
)) {
649 ah
->ah_countryCode
= CTRY_UNITED_STATES
;
653 #ifdef AH_SUPPORT_11D
654 if (ah
->ah_countryCode
== CTRY_DEFAULT
) {
655 regdmn
= ath9k_regd_get_eepromRD(ah
);
659 country
= ath9k_regd_find_country(ah
->ah_countryCode
);
660 if (country
== NULL
) {
661 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
662 "Country is NULL!!!!, cc= %d\n",
666 regdmn
= country
->regDmnEnum
;
667 #ifdef AH_SUPPORT_11D
668 if (((ath9k_regd_get_eepromRD(ah
) &
669 WORLD_SKU_MASK
) == WORLD_SKU_PREFIX
) &&
670 (cc
== CTRY_UNITED_STATES
)) {
671 if (!isWwrSKU_NoMidband(ah
)
672 && ath9k_regd_is_fcc_midband_supported(ah
))
679 #ifdef AH_SUPPORT_11D
682 if (!ath9k_regd_get_wmode_regdomain(ah
,
686 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
687 "Couldn't find unitary "
688 "5GHz reg domain for country %u\n",
692 if (!ath9k_regd_get_wmode_regdomain(ah
,
696 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
697 "Couldn't find unitary 2GHz "
698 "reg domain for country %u\n",
703 if (!isWwrSKU(ah
) && ((rd5GHz
.regDmnEnum
== FCC1
) ||
704 (rd5GHz
.regDmnEnum
== FCC2
))) {
705 if (ath9k_regd_is_fcc_midband_supported(ah
)) {
706 if (!ath9k_regd_get_wmode_regdomain(ah
,
710 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
711 "Couldn't find unitary 5GHz "
712 "reg domain for country %u\n",
719 if (country
== NULL
) {
720 modes_avail
= ah
->ah_caps
.wireless_modes
;
722 ath9k_regd_get_wmodes_nreg(ah
, country
, &rd5GHz
, modes_allowed
);
723 modes_avail
= modes_allowed
;
726 maxChan
= country
->outdoorChanStart
;
731 if (maxchans
> ARRAY_SIZE(ah
->ah_channels
))
732 maxchans
= ARRAY_SIZE(ah
->ah_channels
);
734 for (cm
= modes
; cm
< &modes
[ARRAY_SIZE(modes
)]; cm
++) {
736 u64
*channelBM
= NULL
;
737 struct regDomain
*rd
= NULL
;
738 struct RegDmnFreqBand
*fband
= NULL
, *freqs
;
739 int8_t low_adj
= 0, hi_adj
= 0;
741 if (!test_bit(cm
->mode
, modes_avail
)) {
742 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
743 "!avail mode %d flags 0x%x\n",
744 cm
->mode
, cm
->flags
);
747 if (!ath9k_get_channel_edges(ah
, cm
->flags
, &c_lo
, &c_hi
)) {
748 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
749 "channels 0x%x not supported "
750 "by hardware\n", cm
->flags
);
756 case ATH9K_MODE_11NA_HT20
:
757 case ATH9K_MODE_11NA_HT40PLUS
:
758 case ATH9K_MODE_11NA_HT40MINUS
:
760 channelBM
= rd
->chan11a
;
761 freqs
= ®Dmn5GhzFreq
[0];
762 ctl
= rd
->conformanceTestLimit
;
766 channelBM
= rd
->chan11b
;
767 freqs
= ®Dmn2GhzFreq
[0];
768 ctl
= rd
->conformanceTestLimit
| CTL_11B
;
771 case ATH9K_MODE_11NG_HT20
:
772 case ATH9K_MODE_11NG_HT40PLUS
:
773 case ATH9K_MODE_11NG_HT40MINUS
:
775 channelBM
= rd
->chan11g
;
776 freqs
= ®Dmn2Ghz11gFreq
[0];
777 ctl
= rd
->conformanceTestLimit
| CTL_11G
;
780 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
781 "Unknown HAL mode 0x%x\n", cm
->mode
);
785 if (ath9k_regd_is_chan_bm_zero(channelBM
))
788 if ((cm
->mode
== ATH9K_MODE_11NA_HT40PLUS
) ||
789 (cm
->mode
== ATH9K_MODE_11NG_HT40PLUS
)) {
793 if ((cm
->mode
== ATH9K_MODE_11NA_HT40MINUS
) ||
794 (cm
->mode
== ATH9K_MODE_11NG_HT40MINUS
)) {
798 /* XXX: Add a helper here instead */
799 for (b
= 0; b
< 64 * BMLEN
; b
++) {
800 if (ath9k_regd_is_bit_set(b
, channelBM
)) {
802 if (rd5GHz
.regDmnEnum
== MKK1
803 || rd5GHz
.regDmnEnum
== MKK2
) {
804 if (ath9k_regd_japan_check(ah
,
810 ath9k_regd_add_reg_classid(regclassids
,
816 if (IS_HT40_MODE(cm
->mode
) && (rd
== &rd5GHz
)) {
818 if (fband
->lowChannel
== 5280)
821 if (fband
->lowChannel
== 5170)
824 chanSep
= fband
->channelSep
;
826 for (c
= fband
->lowChannel
+ low_adj
;
827 ((c
<= (fband
->highChannel
+ hi_adj
)) &&
828 (c
>= (fband
->lowChannel
+ low_adj
)));
830 if (next
>= maxchans
) {
834 "for channel table\n");
837 if (ath9k_regd_add_channel(ah
,
844 enableExtendedChannels
))
847 if (IS_HT40_MODE(cm
->mode
) &&
848 (fband
->lowChannel
== 5280)) {
858 if (next
> ARRAY_SIZE(ah
->ah_channels
)) {
859 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
860 "too many channels %u; truncating to %u\n",
861 next
, (int) ARRAY_SIZE(ah
->ah_channels
));
862 next
= ARRAY_SIZE(ah
->ah_channels
);
864 #ifdef ATH_NF_PER_CHAN
865 ath9k_regd_init_rf_buffer(ichans
, next
);
867 ath9k_regd_sort(ichans
, next
,
868 sizeof(struct ath9k_channel
),
869 ath9k_regd_chansort
);
873 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
, "Channel list:\n");
874 for (i
= 0; i
< next
; i
++) {
875 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
876 "chan: %d flags: 0x%x\n",
877 ah
->ah_channels
[i
].channel
,
878 ah
->ah_channels
[i
].channelFlags
);
883 ah
->ah_countryCode
= ah
->ah_countryCode
;
885 ah
->ah_currentRDInUse
= regdmn
;
886 ah
->ah_currentRD5G
= rd5GHz
.regDmnEnum
;
887 ah
->ah_currentRD2G
= rd2GHz
.regDmnEnum
;
888 if (country
== NULL
) {
892 ah
->ah_iso
[0] = country
->isoName
[0];
893 ah
->ah_iso
[1] = country
->isoName
[1];
899 struct ath9k_channel
*
900 ath9k_regd_check_channel(struct ath_hal
*ah
,
901 const struct ath9k_channel
*c
)
903 struct ath9k_channel
*base
, *cc
;
905 int flags
= c
->channelFlags
& CHAN_FLAGS
;
908 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
909 "channel %u/0x%x (0x%x) requested\n",
910 c
->channel
, c
->channelFlags
, flags
);
913 if (cc
!= NULL
&& cc
->channel
== c
->channel
&&
914 (cc
->channelFlags
& CHAN_FLAGS
) == flags
) {
915 if ((cc
->privFlags
& CHANNEL_INTERFERENCE
) &&
916 (cc
->privFlags
& CHANNEL_DFS
))
922 base
= ah
->ah_channels
;
925 for (lim
= n
; lim
!= 0; lim
>>= 1) {
927 cc
= &base
[lim
>> 1];
928 d
= c
->channel
- cc
->channel
;
930 if ((cc
->channelFlags
& CHAN_FLAGS
) == flags
) {
931 if ((cc
->privFlags
& CHANNEL_INTERFERENCE
) &&
932 (cc
->privFlags
& CHANNEL_DFS
))
937 d
= flags
- (cc
->channelFlags
& CHAN_FLAGS
);
939 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
940 "channel %u/0x%x d %d\n",
941 cc
->channel
, cc
->channelFlags
, d
);
947 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
, "no match for %u/0x%x\n",
948 c
->channel
, c
->channelFlags
);
953 ath9k_regd_get_antenna_allowed(struct ath_hal
*ah
,
954 struct ath9k_channel
*chan
)
956 struct ath9k_channel
*ichan
= NULL
;
958 ichan
= ath9k_regd_check_channel(ah
, chan
);
962 return ichan
->antennaMax
;
965 u32
ath9k_regd_get_ctl(struct ath_hal
*ah
, struct ath9k_channel
*chan
)
968 struct ath9k_channel
*ichan
;
970 if (ah
->ah_countryCode
== CTRY_DEFAULT
&& isWwrSKU(ah
)) {
972 ctl
= SD_NO_CTL
| CTL_11B
;
973 else if (IS_CHAN_G(chan
))
974 ctl
= SD_NO_CTL
| CTL_11G
;
976 ctl
= SD_NO_CTL
| CTL_11A
;
978 ichan
= ath9k_regd_check_channel(ah
, chan
);
981 if (IS_CHAN_A(ichan
))
982 ctl
= ichan
->conformanceTestLimit
[0];
983 else if (IS_CHAN_B(ichan
))
984 ctl
= ichan
->conformanceTestLimit
[1];
985 else if (IS_CHAN_G(ichan
))
986 ctl
= ichan
->conformanceTestLimit
[2];
988 if (IS_CHAN_G(chan
) && (ctl
& 0xf) == CTL_11B
)
989 ctl
= (ctl
& ~0xf) | CTL_11G
;
995 void ath9k_regd_get_current_country(struct ath_hal
*ah
,
996 struct ath9k_country_entry
*ctry
)
998 u16 rd
= ath9k_regd_get_eepromRD(ah
);
1000 ctry
->isMultidomain
= false;
1001 if (rd
== CTRY_DEFAULT
)
1002 ctry
->isMultidomain
= true;
1003 else if (!(rd
& COUNTRY_ERD_FLAG
))
1004 ctry
->isMultidomain
= isWwrSKU(ah
);
1006 ctry
->countryCode
= ah
->ah_countryCode
;
1007 ctry
->regDmnEnum
= ah
->ah_currentRD
;
1008 ctry
->regDmn5G
= ah
->ah_currentRD5G
;
1009 ctry
->regDmn2G
= ah
->ah_currentRD2G
;
1010 ctry
->iso
[0] = ah
->ah_iso
[0];
1011 ctry
->iso
[1] = ah
->ah_iso
[1];
1012 ctry
->iso
[2] = ah
->ah_iso
[2];