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