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 "%s: invalid regulatory domain/country code 0x%x\n",
86 static bool ath9k_regd_is_fcc_midband_supported(struct ath_hal
*ah
)
90 regcap
= ah
->ah_caps
.reg_cap
;
92 if (regcap
& AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND
)
98 static bool ath9k_regd_is_ccode_valid(struct ath_hal
*ah
,
104 if (cc
== CTRY_DEFAULT
)
106 if (cc
== CTRY_DEBUG
)
109 rd
= ath9k_regd_get_eepromRD(ah
);
110 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
, "%s: EEPROM regdomain 0x%x\n",
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
);
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
)
126 if (allCountries
[i
].regDmnEnum
== rd
||
127 rd
== DEBUG_REG_DMN
|| rd
== NO_ENUMRD
)
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
)
140 bitmap_copy(modes_allowed
, ah
->ah_caps
.wireless_modes
, ATH9K_MODE_MAX
);
142 if (test_bit(ATH9K_MODE_11G
, ah
->ah_caps
.wireless_modes
) &&
143 (!country
->allow11g
))
144 clear_bit(ATH9K_MODE_11G
, modes_allowed
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
175 bool ath9k_regd_is_public_safety_sku(struct ath_hal
*ah
)
179 rd
= ath9k_regd_get_eepromRD(ah
);
183 case (CTRY_UNITED_STATES_FCC49
| COUNTRY_ERD_FLAG
):
187 if (ah
->ah_countryCode
== CTRY_UNITED_STATES_FCC49
)
194 static struct country_code_to_enum_rd
*
195 ath9k_regd_find_country(u16 countryCode
)
199 for (i
= 0; i
< ARRAY_SIZE(allCountries
); i
++) {
200 if (allCountries
[i
].countryCode
== countryCode
)
201 return &allCountries
[i
];
206 static u16
ath9k_regd_get_default_country(struct ath_hal
*ah
)
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
;
216 country
= ath9k_regd_find_country(cc
);
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
;
226 i
= ARRAY_SIZE(regDomainPairs
);
231 static bool ath9k_regd_is_valid_reg_domain(int regDmn
,
232 struct regDomain
*rd
)
236 for (i
= 0; i
< ARRAY_SIZE(regDomains
); i
++) {
237 if (regDomains
[i
].regDmnEnum
== regDmn
) {
239 memcpy(rd
, ®Domains
[i
],
240 sizeof(struct regDomain
));
248 static bool ath9k_regd_is_valid_reg_domainPair(int regDmnPair
)
252 if (regDmnPair
== NO_ENUMRD
)
254 for (i
= 0; i
< ARRAY_SIZE(regDomainPairs
); i
++) {
255 if (regDomainPairs
[i
].regDmnEnum
== regDmnPair
)
262 ath9k_regd_get_wmode_regdomain(struct ath_hal
*ah
, int regDmn
,
263 u16 channelFlag
, struct regDomain
*rd
)
267 struct reg_dmn_pair_mapping
*regPair
= NULL
;
271 if (regDmn
== CTRY_DEFAULT
) {
273 rdnum
= ath9k_regd_get_eepromRD(ah
);
275 if (!(rdnum
& COUNTRY_ERD_FLAG
)) {
276 if (ath9k_regd_is_valid_reg_domain(rdnum
, NULL
) ||
277 ath9k_regd_is_valid_reg_domainPair(rdnum
)) {
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
= ®DomainPairs
[i
];
292 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
293 "%s: Failed to find reg domain pair %u\n",
297 if (!(channelFlag
& CHANNEL_2GHZ
)) {
298 regDmn
= regPair
->regDmn5GHz
;
299 flags
= regPair
->flags5GHz
;
301 if (channelFlag
& CHANNEL_2GHZ
) {
302 regDmn
= regPair
->regDmn2GHz
;
303 flags
= regPair
->flags2GHz
;
307 found
= ath9k_regd_is_valid_reg_domain(regDmn
, rd
);
309 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
310 "%s: Failed to find unitary reg domain %u\n",
314 rd
->pscan
&= regPair
->pscanMask
;
315 if (((regOrg
& MULTI_DOMAIN_MASK
) == 0) &&
320 rd
->flags
&= (channelFlag
& CHANNEL_2GHZ
) ?
321 REG_DOMAIN_2GHZ_MASK
: REG_DOMAIN_5GHZ_MASK
;
326 static bool ath9k_regd_is_bit_set(int bit
, u64
*bitmask
)
328 int byteOffset
, bitnum
;
331 byteOffset
= bit
/ 64;
332 bitnum
= bit
- byteOffset
* 64;
333 val
= ((u64
) 1) << bitnum
;
334 if (bitmask
[byteOffset
] & val
)
341 ath9k_regd_add_reg_classid(u8
*regclassids
, u32 maxregids
,
342 u32
*nregids
, u8 regclassid
)
349 for (i
= 0; i
< maxregids
; i
++) {
350 if (regclassids
[i
] == regclassid
)
352 if (regclassids
[i
] == 0)
359 regclassids
[i
] = regclassid
;
367 ath9k_regd_get_eeprom_reg_ext_bits(struct ath_hal
*ah
,
368 enum reg_ext_bitmap bit
)
370 return (ah
->ah_currentRDExt
& (1 << bit
)) ? true : false;
373 #ifdef ATH_NF_PER_CHAN
375 static void ath9k_regd_init_rf_buffer(struct ath9k_channel
*ichans
,
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
;
396 static int ath9k_regd_is_chan_present(struct ath_hal
*ah
,
401 for (i
= 0; i
< 150; i
++) {
402 if (!ah
->ah_channels
[i
].channel
)
404 else if (ah
->ah_channels
[i
].channel
== c
)
412 ath9k_regd_add_channel(struct ath_hal
*ah
,
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
)
426 struct ath9k_channel
*chan
;
428 u32 channelFlags
= 0;
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
);
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",
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",
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
);
460 if ((fband
->usePassScan
& IS_ECM_CHAN
) && !enableExtendedChannels
) {
461 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
462 "Skipping ecm channel\n");
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");
472 if (IS_HT40_MODE(cm
->mode
) &&
473 !(ath9k_regd_get_eeprom_reg_ext_bits(ah
, REG_EXT_FCC_DFS_HT40
)) &&
475 (rd
->conformanceTestLimit
!= MKK
)) {
476 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
477 "Skipping HT40 channel (en_fcc_dfs_ht40 = 0)\n");
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");
490 if (IS_HT40_MODE(cm
->mode
) &&
491 !(ath9k_regd_get_eeprom_reg_ext_bits(ah
, REG_EXT_JAPAN_DFS_HT40
)) &&
493 (rd
->conformanceTestLimit
== MKK
)) {
494 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
495 "Skipping HT40 channel (en_jap_dfs_ht40 = 0)\n");
499 /* Calculate channel flags */
501 channelFlags
= cm
->flags
;
503 switch (fband
->channelBW
) {
504 case CHANNEL_HALF_BW
:
505 channelFlags
|= CHANNEL_HALF
;
507 case CHANNEL_QUARTER_BW
:
508 channelFlags
|= CHANNEL_QUARTER
;
512 if (fband
->usePassScan
& rd
->pscan
)
513 channelFlags
|= CHANNEL_PASSIVE
;
515 channelFlags
&= ~CHANNEL_PASSIVE
;
516 if (fband
->useDfs
& rd
->dfsMask
)
517 privFlags
= CHANNEL_DFS
;
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
;
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
;
533 (AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN
|
534 AR_EEPROM_EEREGCAP_EN_KK_U2
|
535 AR_EEPROM_EEREGCAP_EN_KK_MIDBAND
)) &&
537 channelFlags
&= ~CHANNEL_PASSIVE
;
539 privFlags
|= CHANNEL_DISALLOW_ADHOC
;
542 privFlags
|= CHANNEL_DISALLOW_ADHOC
;
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
;
555 /* Fill in channel details */
557 ret
= ath9k_regd_is_chan_present(ah
, c
);
559 chan
= &ah
->ah_channels
[pos
];
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
;
569 chan
= &ah
->ah_channels
[ret
];
570 chan
->channelFlags
|= channelFlags
;
571 chan
->privFlags
|= privFlags
;
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
;
583 return (ret
== -1) ? true : false;
586 static bool ath9k_regd_japan_check(struct ath_hal
*ah
,
588 struct regDomain
*rd5GHz
)
590 bool skipband
= false;
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) {
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
;
608 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
609 "%s: Skipping %d freq band\n",
610 __func__
, j_bandcheck
[i
].freqbandbit
);
616 ath9k_regd_init_channels(struct ath_hal
*ah
,
618 u32
*nchans
, u8
*regclassids
,
619 u32 maxregids
, u32
*nregids
, u16 cc
,
621 bool enableExtendedChannels
)
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];
632 unsigned long *modes_avail
;
633 DECLARE_BITMAP(modes_allowed
, ATH9K_MODE_MAX
);
635 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
, "%s: cc %u %s %s\n",
637 enableOutdoor
? "Enable outdoor" : "",
638 enableExtendedChannels
? "Enable ecm" : "");
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
);
646 if (!ath9k_regd_is_eeprom_valid(ah
)) {
647 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
648 "%s: invalid EEPROM contents\n", __func__
);
652 ah
->ah_countryCode
= ath9k_regd_get_default_country(ah
);
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
;
662 #ifdef AH_SUPPORT_11D
663 if (ah
->ah_countryCode
== CTRY_DEFAULT
) {
664 regdmn
= ath9k_regd_get_eepromRD(ah
);
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",
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
))
688 #ifdef AH_SUPPORT_11D
691 if (!ath9k_regd_get_wmode_regdomain(ah
,
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
);
701 if (!ath9k_regd_get_wmode_regdomain(ah
,
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
);
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
,
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
);
728 if (country
== NULL
) {
729 modes_avail
= ah
->ah_caps
.wireless_modes
;
731 ath9k_regd_get_wmodes_nreg(ah
, country
, &rd5GHz
, modes_allowed
);
732 modes_avail
= modes_allowed
;
735 maxChan
= country
->outdoorChanStart
;
740 if (maxchans
> ARRAY_SIZE(ah
->ah_channels
))
741 maxchans
= ARRAY_SIZE(ah
->ah_channels
);
743 for (cm
= modes
; cm
< &modes
[ARRAY_SIZE(modes
)]; cm
++) {
745 u64
*channelBM
= NULL
;
746 struct regDomain
*rd
= NULL
;
747 struct RegDmnFreqBand
*fband
= NULL
, *freqs
;
748 int8_t low_adj
= 0, hi_adj
= 0;
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
);
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 "
760 __func__
, cm
->flags
);
766 case ATH9K_MODE_11NA_HT20
:
767 case ATH9K_MODE_11NA_HT40PLUS
:
768 case ATH9K_MODE_11NA_HT40MINUS
:
770 channelBM
= rd
->chan11a
;
771 freqs
= ®Dmn5GhzFreq
[0];
772 ctl
= rd
->conformanceTestLimit
;
776 channelBM
= rd
->chan11b
;
777 freqs
= ®Dmn2GhzFreq
[0];
778 ctl
= rd
->conformanceTestLimit
| CTL_11B
;
781 case ATH9K_MODE_11NG_HT20
:
782 case ATH9K_MODE_11NG_HT40PLUS
:
783 case ATH9K_MODE_11NG_HT40MINUS
:
785 channelBM
= rd
->chan11g
;
786 freqs
= ®Dmn2Ghz11gFreq
[0];
787 ctl
= rd
->conformanceTestLimit
| CTL_11G
;
790 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
791 "%s: Unknown HAL mode 0x%x\n", __func__
,
796 if (ath9k_regd_is_chan_bm_zero(channelBM
))
799 if ((cm
->mode
== ATH9K_MODE_11NA_HT40PLUS
) ||
800 (cm
->mode
== ATH9K_MODE_11NG_HT40PLUS
)) {
804 if ((cm
->mode
== ATH9K_MODE_11NA_HT40MINUS
) ||
805 (cm
->mode
== ATH9K_MODE_11NG_HT40MINUS
)) {
809 /* XXX: Add a helper here instead */
810 for (b
= 0; b
< 64 * BMLEN
; b
++) {
811 if (ath9k_regd_is_bit_set(b
, channelBM
)) {
813 if (rd5GHz
.regDmnEnum
== MKK1
814 || rd5GHz
.regDmnEnum
== MKK2
) {
815 if (ath9k_regd_japan_check(ah
,
821 ath9k_regd_add_reg_classid(regclassids
,
827 if (IS_HT40_MODE(cm
->mode
) && (rd
== &rd5GHz
)) {
829 if (fband
->lowChannel
== 5280)
832 if (fband
->lowChannel
== 5170)
835 chanSep
= fband
->channelSep
;
837 for (c
= fband
->lowChannel
+ low_adj
;
838 ((c
<= (fband
->highChannel
+ hi_adj
)) &&
839 (c
>= (fband
->lowChannel
+ low_adj
)));
841 if (next
>= maxchans
) {
844 "%s: too many channels "
845 "for channel table\n",
849 if (ath9k_regd_add_channel(ah
,
856 enableExtendedChannels
))
859 if (IS_HT40_MODE(cm
->mode
) &&
860 (fband
->lowChannel
== 5280)) {
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",
874 (int) ARRAY_SIZE(ah
->ah_channels
));
875 next
= ARRAY_SIZE(ah
->ah_channels
);
877 #ifdef ATH_NF_PER_CHAN
878 ath9k_regd_init_rf_buffer(ichans
, next
);
880 ath9k_regd_sort(ichans
, next
,
881 sizeof(struct ath9k_channel
),
882 ath9k_regd_chansort
);
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
);
896 ah
->ah_countryCode
= ah
->ah_countryCode
;
898 ah
->ah_currentRDInUse
= regdmn
;
899 ah
->ah_currentRD5G
= rd5GHz
.regDmnEnum
;
900 ah
->ah_currentRD2G
= rd2GHz
.regDmnEnum
;
901 if (country
== NULL
) {
905 ah
->ah_iso
[0] = country
->isoName
[0];
906 ah
->ah_iso
[1] = country
->isoName
[1];
912 struct ath9k_channel
*
913 ath9k_regd_check_channel(struct ath_hal
*ah
,
914 const struct ath9k_channel
*c
)
916 struct ath9k_channel
*base
, *cc
;
918 int flags
= c
->channelFlags
& CHAN_FLAGS
;
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
);
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
))
935 base
= ah
->ah_channels
;
938 for (lim
= n
; lim
!= 0; lim
>>= 1) {
940 cc
= &base
[lim
>> 1];
941 d
= c
->channel
- cc
->channel
;
943 if ((cc
->channelFlags
& CHAN_FLAGS
) == flags
) {
944 if ((cc
->privFlags
& CHANNEL_INTERFERENCE
) &&
945 (cc
->privFlags
& CHANNEL_DFS
))
950 d
= flags
- (cc
->channelFlags
& CHAN_FLAGS
);
952 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
,
953 "%s: channel %u/0x%x d %d\n", __func__
,
954 cc
->channel
, cc
->channelFlags
, d
);
960 DPRINTF(ah
->ah_sc
, ATH_DBG_REGULATORY
, "%s: no match for %u/0x%x\n",
961 __func__
, c
->channel
, c
->channelFlags
);
966 ath9k_regd_get_antenna_allowed(struct ath_hal
*ah
,
967 struct ath9k_channel
*chan
)
969 struct ath9k_channel
*ichan
= NULL
;
971 ichan
= ath9k_regd_check_channel(ah
, chan
);
975 return ichan
->antennaMax
;
978 u32
ath9k_regd_get_ctl(struct ath_hal
*ah
, struct ath9k_channel
*chan
)
981 struct ath9k_channel
*ichan
;
983 if (ah
->ah_countryCode
== CTRY_DEFAULT
&& isWwrSKU(ah
)) {
985 ctl
= SD_NO_CTL
| CTL_11B
;
986 else if (IS_CHAN_G(chan
))
987 ctl
= SD_NO_CTL
| CTL_11G
;
989 ctl
= SD_NO_CTL
| CTL_11A
;
991 ichan
= ath9k_regd_check_channel(ah
, chan
);
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];
1001 if (IS_CHAN_G(chan
) && (ctl
& 0xf) == CTL_11B
)
1002 ctl
= (ctl
& ~0xf) | CTL_11G
;
1008 void ath9k_regd_get_current_country(struct ath_hal
*ah
,
1009 struct ath9k_country_entry
*ctry
)
1011 u16 rd
= ath9k_regd_get_eepromRD(ah
);
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
);
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];