xref: /freebsd/sys/dev/ath/ath_hal/ah_regdomain.c (revision cab6a39d7b343596a5823e65c0f7b426551ec22d)
1 /*-
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
5  * Copyright (c) 2005-2006 Atheros Communications, Inc.
6  * All rights reserved.
7  *
8  * Permission to use, copy, modify, and/or distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  *
20  * $FreeBSD$
21  */
22 #include "opt_ah.h"
23 
24 #include "ah.h"
25 
26 #include <net80211/_ieee80211.h>
27 #include <net80211/ieee80211_regdomain.h>
28 
29 #include "ah_internal.h"
30 #include "ah_eeprom.h"
31 #include "ah_devid.h"
32 
33 #include "ah_regdomain.h"
34 
35 /*
36  * XXX this code needs a audit+review
37  */
38 
39 /* used throughout this file... */
40 #define	N(a)		nitems(a)
41 
42 #define HAL_MODE_11A_TURBO	HAL_MODE_108A
43 #define HAL_MODE_11G_TURBO	HAL_MODE_108G
44 
45 /*
46  * Mask to check whether a domain is a multidomain or a single domain
47  */
48 #define MULTI_DOMAIN_MASK 0xFF00
49 
50 /*
51  * Enumerated Regulatory Domain Information 8 bit values indicate that
52  * the regdomain is really a pair of unitary regdomains.  12 bit values
53  * are the real unitary regdomains and are the only ones which have the
54  * frequency bitmasks and flags set.
55  */
56 #include "ah_regdomain/ah_rd_regenum.h"
57 
58 #define	WORLD_SKU_MASK		0x00F0
59 #define	WORLD_SKU_PREFIX	0x0060
60 
61 /*
62  * THE following table is the mapping of regdomain pairs specified by
63  * an 8 bit regdomain value to the individual unitary reg domains
64  */
65 #include "ah_regdomain/ah_rd_regmap.h"
66 
67 /*
68  * The following tables are the master list for all different freqeuncy
69  * bands with the complete matrix of all possible flags and settings
70  * for each band if it is used in ANY reg domain.
71  */
72 
73 #define	COUNTRY_ERD_FLAG        0x8000
74 #define WORLDWIDE_ROAMING_FLAG  0x4000
75 
76 /*
77  * This table maps country ISO codes from net80211 into regulatory
78  * domains which the ath regulatory domain code understands.
79  */
80 #include "ah_regdomain/ah_rd_ctry.h"
81 
82 /*
83  * The frequency band collections are a set of frequency ranges
84  * with shared properties - max tx power, max antenna gain, channel width,
85  * channel spacing, DFS requirements and passive scanning requirements.
86  *
87  * These are represented as entries in a frequency band bitmask.
88  * Each regulatory domain entry in ah_regdomain_domains.h uses one
89  * or more frequency band entries for each of the channel modes
90  * supported (11bg, 11a, half, quarter, turbo, etc.)
91  *
92  */
93 #include "ah_regdomain/ah_rd_freqbands.h"
94 
95 /*
96  * This is the main regulatory database. It defines the supported
97  * set of features and requirements for each of the defined regulatory
98  * zones. It uses combinations of frequency ranges - represented in
99  * a bitmask - to determine the requirements and limitations needed.
100  */
101 #include "ah_regdomain/ah_rd_domains.h"
102 
103 static const struct cmode modes[] = {
104 	{ HAL_MODE_TURBO,	IEEE80211_CHAN_ST,	&regDmn5GhzTurboFreq[0] },
105 	{ HAL_MODE_11A,		IEEE80211_CHAN_A,	&regDmn5GhzFreq[0] },
106 	{ HAL_MODE_11B,		IEEE80211_CHAN_B,	&regDmn2GhzFreq[0] },
107 	{ HAL_MODE_11G,		IEEE80211_CHAN_G,	&regDmn2Ghz11gFreq[0] },
108 	{ HAL_MODE_11G_TURBO,	IEEE80211_CHAN_108G,	&regDmn2Ghz11gTurboFreq[0] },
109 	{ HAL_MODE_11A_TURBO,	IEEE80211_CHAN_108A,	&regDmn5GhzTurboFreq[0] },
110 	{ HAL_MODE_11A_QUARTER_RATE,
111 	  IEEE80211_CHAN_A | IEEE80211_CHAN_QUARTER,	&regDmn5GhzFreq[0] },
112 	{ HAL_MODE_11A_HALF_RATE,
113 	  IEEE80211_CHAN_A | IEEE80211_CHAN_HALF,	&regDmn5GhzFreq[0] },
114 	{ HAL_MODE_11G_QUARTER_RATE,
115 	  IEEE80211_CHAN_G | IEEE80211_CHAN_QUARTER,	&regDmn2Ghz11gFreq[0] },
116 	{ HAL_MODE_11G_HALF_RATE,
117 	  IEEE80211_CHAN_G | IEEE80211_CHAN_HALF,	&regDmn2Ghz11gFreq[0] },
118 	{ HAL_MODE_11NG_HT20,
119 	  IEEE80211_CHAN_G | IEEE80211_CHAN_HT20,	&regDmn2Ghz11gFreq[0] },
120 	{ HAL_MODE_11NG_HT40PLUS,
121 	  IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U,	&regDmn2Ghz11gFreq[0] },
122 	{ HAL_MODE_11NG_HT40MINUS,
123 	  IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D,	&regDmn2Ghz11gFreq[0] },
124 	{ HAL_MODE_11NA_HT20,
125 	  IEEE80211_CHAN_A | IEEE80211_CHAN_HT20,	&regDmn5GhzFreq[0] },
126 	{ HAL_MODE_11NA_HT40PLUS,
127 	  IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U,	&regDmn5GhzFreq[0] },
128 	{ HAL_MODE_11NA_HT40MINUS,
129 	  IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D,	&regDmn5GhzFreq[0] },
130 };
131 
132 static void ath_hal_update_dfsdomain(struct ath_hal *ah);
133 
134 static OS_INLINE uint16_t
135 getEepromRD(struct ath_hal *ah)
136 {
137 	return AH_PRIVATE(ah)->ah_currentRD &~ WORLDWIDE_ROAMING_FLAG;
138 }
139 
140 /*
141  * Test to see if the bitmask array is all zeros
142  */
143 static HAL_BOOL
144 isChanBitMaskZero(const uint64_t *bitmask)
145 {
146 #if BMLEN > 2
147 #error	"add more cases"
148 #endif
149 #if BMLEN > 1
150 	if (bitmask[1] != 0)
151 		return AH_FALSE;
152 #endif
153 	return (bitmask[0] == 0);
154 }
155 
156 /*
157  * Return whether or not the regulatory domain/country in EEPROM
158  * is acceptable.
159  */
160 static HAL_BOOL
161 isEepromValid(struct ath_hal *ah)
162 {
163 	uint16_t rd = getEepromRD(ah);
164 	int i;
165 
166 	if (rd & COUNTRY_ERD_FLAG) {
167 		uint16_t cc = rd &~ COUNTRY_ERD_FLAG;
168 		for (i = 0; i < N(allCountries); i++)
169 			if (allCountries[i].countryCode == cc)
170 				return AH_TRUE;
171 	} else {
172 		for (i = 0; i < N(regDomainPairs); i++)
173 			if (regDomainPairs[i].regDmnEnum == rd)
174 				return AH_TRUE;
175 	}
176 
177 	if (rd == FCC_UBNT) {
178 		return AH_TRUE;
179 	}
180 
181 	HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
182 	    "%s: invalid regulatory domain/country code 0x%x\n", __func__, rd);
183 	return AH_FALSE;
184 }
185 
186 /*
187  * Find the pointer to the country element in the country table
188  * corresponding to the country code
189  */
190 static COUNTRY_CODE_TO_ENUM_RD*
191 findCountry(HAL_CTRY_CODE countryCode)
192 {
193 	int i;
194 
195 	for (i = 0; i < N(allCountries); i++) {
196 		if (allCountries[i].countryCode == countryCode)
197 			return &allCountries[i];
198 	}
199 	return AH_NULL;
200 }
201 
202 static REG_DOMAIN *
203 findRegDmn(int regDmn)
204 {
205 	int i;
206 
207 	for (i = 0; i < N(regDomains); i++) {
208 		if (regDomains[i].regDmnEnum == regDmn)
209 			return &regDomains[i];
210 	}
211 	return AH_NULL;
212 }
213 
214 static REG_DMN_PAIR_MAPPING *
215 findRegDmnPair(int regDmnPair)
216 {
217 	int i;
218 
219 	if (regDmnPair != NO_ENUMRD) {
220 		for (i = 0; i < N(regDomainPairs); i++) {
221 			if (regDomainPairs[i].regDmnEnum == regDmnPair)
222 				return &regDomainPairs[i];
223 		}
224 	}
225 	return AH_NULL;
226 }
227 
228 /*
229  * Calculate a default country based on the EEPROM setting.
230  */
231 static HAL_CTRY_CODE
232 getDefaultCountry(struct ath_hal *ah)
233 {
234 	REG_DMN_PAIR_MAPPING *regpair;
235 	uint16_t rd;
236 
237 	rd = getEepromRD(ah);
238 	if (rd & COUNTRY_ERD_FLAG) {
239 		COUNTRY_CODE_TO_ENUM_RD *country;
240 		uint16_t cc = rd & ~COUNTRY_ERD_FLAG;
241 		country = findCountry(cc);
242 		if (country != AH_NULL)
243 			return cc;
244 	}
245 	/*
246 	 * Check reg domains that have only one country
247 	 */
248 	regpair = findRegDmnPair(rd);
249 	return (regpair != AH_NULL) ? regpair->singleCC : CTRY_DEFAULT;
250 }
251 
252 static HAL_BOOL
253 IS_BIT_SET(int bit, const uint64_t bitmask[])
254 {
255 	int byteOffset, bitnum;
256 	uint64_t val;
257 
258 	byteOffset = bit/64;
259 	bitnum = bit - byteOffset*64;
260 	val = ((uint64_t) 1) << bitnum;
261 	return (bitmask[byteOffset] & val) != 0;
262 }
263 
264 static HAL_STATUS
265 getregstate(struct ath_hal *ah, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
266     COUNTRY_CODE_TO_ENUM_RD **pcountry,
267     REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz)
268 {
269 	COUNTRY_CODE_TO_ENUM_RD *country;
270 	REG_DOMAIN *rd5GHz, *rd2GHz;
271 
272 	if (cc == CTRY_DEFAULT && regDmn == SKU_NONE) {
273 		/*
274 		 * Validate the EEPROM setting and setup defaults
275 		 */
276 		if (!isEepromValid(ah)) {
277 			/*
278 			 * Don't return any channels if the EEPROM has an
279 			 * invalid regulatory domain/country code setting.
280 			 */
281 			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
282 			    "%s: invalid EEPROM contents\n",__func__);
283 			return HAL_EEBADREG;
284 		}
285 
286 		cc = getDefaultCountry(ah);
287 		country = findCountry(cc);
288 		if (country == AH_NULL) {
289 			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
290 			    "NULL Country!, cc %d\n", cc);
291 			return HAL_EEBADCC;
292 		}
293 		regDmn = country->regDmnEnum;
294 		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: EEPROM cc %u rd 0x%x\n",
295 		    __func__, cc, regDmn);
296 
297 		if (country->countryCode == CTRY_DEFAULT) {
298 			/*
299 			 * Check EEPROM; SKU may be for a country, single
300 			 * domain, or multiple domains (WWR).
301 			 */
302 			uint16_t rdnum = getEepromRD(ah);
303 			if ((rdnum & COUNTRY_ERD_FLAG) == 0 &&
304 			    (findRegDmn(rdnum) != AH_NULL ||
305 			     findRegDmnPair(rdnum) != AH_NULL)) {
306 				regDmn = rdnum;
307 				HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
308 				    "%s: EEPROM rd 0x%x\n", __func__, rdnum);
309 			}
310 		}
311 	} else {
312 		country = findCountry(cc);
313 		if (country == AH_NULL) {
314 			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
315 			    "unknown country, cc %d\n", cc);
316 			return HAL_EINVAL;
317 		}
318 		if (regDmn == SKU_NONE)
319 			regDmn = country->regDmnEnum;
320 		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u rd 0x%x\n",
321 		    __func__, cc, regDmn);
322 	}
323 
324 	/*
325 	 * Setup per-band state.
326 	 */
327 	if ((regDmn & MULTI_DOMAIN_MASK) == 0) {
328 		REG_DMN_PAIR_MAPPING *regpair = findRegDmnPair(regDmn);
329 		if (regpair == AH_NULL) {
330 			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
331 			    "%s: no reg domain pair %u for country %u\n",
332 			    __func__, regDmn, country->countryCode);
333 			return HAL_EINVAL;
334 		}
335 		rd5GHz = findRegDmn(regpair->regDmn5GHz);
336 		if (rd5GHz == AH_NULL) {
337 			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
338 			    "%s: no 5GHz reg domain %u for country %u\n",
339 			    __func__, regpair->regDmn5GHz, country->countryCode);
340 			return HAL_EINVAL;
341 		}
342 		rd2GHz = findRegDmn(regpair->regDmn2GHz);
343 		if (rd2GHz == AH_NULL) {
344 			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
345 			    "%s: no 2GHz reg domain %u for country %u\n",
346 			    __func__, regpair->regDmn2GHz, country->countryCode);
347 			return HAL_EINVAL;
348 		}
349 	} else {
350 		rd5GHz = rd2GHz = findRegDmn(regDmn);
351 		if (rd2GHz == AH_NULL) {
352 			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
353 			    "%s: no unitary reg domain %u for country %u\n",
354 			    __func__, regDmn, country->countryCode);
355 			return HAL_EINVAL;
356 		}
357 	}
358 	if (pcountry != AH_NULL)
359 		*pcountry = country;
360 	*prd2GHz = rd2GHz;
361 	*prd5GHz = rd5GHz;
362 	return HAL_OK;
363 }
364 
365 static uint64_t *
366 getchannelBM(u_int mode, REG_DOMAIN *rd)
367 {
368 	switch (mode) {
369 	case HAL_MODE_11B:
370 		return (rd->chan11b);
371 	case HAL_MODE_11G_QUARTER_RATE:
372 		return (rd->chan11g_quarter);
373 	case HAL_MODE_11G_HALF_RATE:
374 		return (rd->chan11g_half);
375 	case HAL_MODE_11G:
376 	case HAL_MODE_11NG_HT20:
377 	case HAL_MODE_11NG_HT40PLUS:
378 	case HAL_MODE_11NG_HT40MINUS:
379 		return (rd->chan11g);
380 	case HAL_MODE_11G_TURBO:
381 		return (rd->chan11g_turbo);
382 	case HAL_MODE_11A_QUARTER_RATE:
383 		return (rd->chan11a_quarter);
384 	case HAL_MODE_11A_HALF_RATE:
385 		return (rd->chan11a_half);
386 	case HAL_MODE_11A:
387 	case HAL_MODE_11NA_HT20:
388 	case HAL_MODE_11NA_HT40PLUS:
389 	case HAL_MODE_11NA_HT40MINUS:
390 		return (rd->chan11a);
391 	case HAL_MODE_TURBO:
392 		return (rd->chan11a_turbo);
393 	case HAL_MODE_11A_TURBO:
394 		return (rd->chan11a_dyn_turbo);
395 	default:
396 		return (AH_NULL);
397 	}
398 }
399 
400 static void
401 setchannelflags(struct ieee80211_channel *c, REG_DMN_FREQ_BAND *fband,
402     REG_DOMAIN *rd)
403 {
404 	if (fband->usePassScan & rd->pscan)
405 		c->ic_flags |= IEEE80211_CHAN_PASSIVE;
406 	if (fband->useDfs & rd->dfsMask)
407 		c->ic_flags |= IEEE80211_CHAN_DFS;
408 	if (IEEE80211_IS_CHAN_5GHZ(c) && (rd->flags & DISALLOW_ADHOC_11A))
409 		c->ic_flags |= IEEE80211_CHAN_NOADHOC;
410 	if (IEEE80211_IS_CHAN_TURBO(c) &&
411 	    (rd->flags & DISALLOW_ADHOC_11A_TURB))
412 		c->ic_flags |= IEEE80211_CHAN_NOADHOC;
413 	if (rd->flags & NO_HOSTAP)
414 		c->ic_flags |= IEEE80211_CHAN_NOHOSTAP;
415 	if (rd->flags & LIMIT_FRAME_4MS)
416 		c->ic_flags |= IEEE80211_CHAN_4MSXMIT;
417 	if (rd->flags & NEED_NFC)
418 		c->ic_flags |= CHANNEL_NFCREQUIRED;
419 }
420 
421 static int
422 addchan(struct ath_hal *ah, struct ieee80211_channel chans[],
423     u_int maxchans, int *nchans, uint16_t freq, uint32_t flags,
424     REG_DMN_FREQ_BAND *fband, REG_DOMAIN *rd)
425 {
426 	struct ieee80211_channel *c;
427 
428 	if (*nchans >= maxchans)
429 		return (HAL_ENOMEM);
430 
431 	HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
432 	    "%s: %d: freq=%d, flags=0x%08x\n",
433 	    __func__, *nchans, (int) freq, flags);
434 
435 	c = &chans[(*nchans)++];
436 	c->ic_freq = freq;
437 	c->ic_flags = flags;
438 	setchannelflags(c, fband, rd);
439 	c->ic_maxregpower = fband->powerDfs;
440 	ath_hal_getpowerlimits(ah, c);
441 	c->ic_maxantgain = fband->antennaMax;
442 
443 	return (0);
444 }
445 
446 static int
447 copychan_prev(struct ath_hal *ah, struct ieee80211_channel chans[],
448     u_int maxchans, int *nchans, uint16_t freq, uint32_t flags)
449 {
450 	struct ieee80211_channel *c;
451 
452 	if (*nchans == 0)
453 		return (HAL_EINVAL);
454 
455 	if (*nchans >= maxchans)
456 		return (HAL_ENOMEM);
457 
458 	HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
459 	    "%s: %d: freq=%d, flags=0x%08x\n",
460 	    __func__, *nchans, (int) freq, flags);
461 
462 	c = &chans[(*nchans)++];
463 	c[0] = c[-1];
464 	c->ic_freq = freq;
465 	/* XXX is it needed here? */
466 	ath_hal_getpowerlimits(ah, c);
467 
468 	return (0);
469 }
470 
471 static int
472 add_chanlist_band(struct ath_hal *ah, struct ieee80211_channel chans[],
473     int maxchans, int *nchans, uint16_t freq_lo, uint16_t freq_hi, int step,
474     uint32_t flags, REG_DMN_FREQ_BAND *fband, REG_DOMAIN *rd)
475 {
476 	uint16_t freq = freq_lo;
477 	int error;
478 
479 	if (freq_hi < freq_lo)
480 		return (0);
481 
482 	HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
483 	    "%s: freq=%d..%d, flags=0x%08x, step=%d\n", __func__,
484 	    (int) freq_lo, (int) freq_hi, flags, step);
485 
486 	error = addchan(ah, chans, maxchans, nchans, freq, flags, fband, rd);
487 	for (freq += step; freq <= freq_hi && error == 0; freq += step)
488 		error = copychan_prev(ah, chans, maxchans, nchans, freq, flags);
489 
490 	return (error);
491 }
492 
493 static void
494 adj_freq_ht40(u_int mode, int *low_adj, int *hi_adj, int *channelSep)
495 {
496 
497 	*low_adj = *hi_adj = *channelSep = 0;
498 	switch (mode) {
499 	case HAL_MODE_11NA_HT40PLUS:
500 		*channelSep = 40;
501 		/* FALLTHROUGH */
502 	case HAL_MODE_11NG_HT40PLUS:
503 		*hi_adj = -20;
504 		break;
505 	case HAL_MODE_11NA_HT40MINUS:
506 		*channelSep = 40;
507 		/* FALLTHROUGH */
508 	case HAL_MODE_11NG_HT40MINUS:
509 		*low_adj = 20;
510 		break;
511 	}
512 }
513 
514 static void
515 add_chanlist_mode(struct ath_hal *ah, struct ieee80211_channel chans[],
516     u_int maxchans, int *nchans, const struct cmode *cm, REG_DOMAIN *rd,
517     HAL_BOOL enableExtendedChannels)
518 {
519 	uint64_t *channelBM;
520 	uint16_t freq_lo, freq_hi;
521 	int b, error, low_adj, hi_adj, channelSep;
522 
523 	if (!ath_hal_getChannelEdges(ah, cm->flags, &freq_lo, &freq_hi)) {
524 		/* channel not supported by hardware, skip it */
525 		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
526 		    "%s: channels 0x%x not supported by hardware\n",
527 		    __func__, cm->flags);
528 		return;
529 	}
530 
531 	channelBM = getchannelBM(cm->mode, rd);
532 	if (isChanBitMaskZero(channelBM))
533 		return;
534 
535 	/*
536 	 * Setup special handling for HT40 channels; e.g.
537 	 * 5G HT40 channels require 40Mhz channel separation.
538 	 */
539 	adj_freq_ht40(cm->mode, &low_adj, &hi_adj, &channelSep);
540 
541 	for (b = 0; b < 64*BMLEN; b++) {
542 		REG_DMN_FREQ_BAND *fband;
543 		uint16_t bfreq_lo, bfreq_hi;
544 		int step;
545 
546 		if (!IS_BIT_SET(b, channelBM))
547 			continue;
548 		fband = &cm->freqs[b];
549 
550 		if ((fband->usePassScan & IS_ECM_CHAN) &&
551 		    !enableExtendedChannels) {
552 			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
553 			    "skip ecm channels\n");
554 			continue;
555 		}
556 #if 0
557 		if ((fband->useDfs & rd->dfsMask) &&
558 		    (cm->flags & IEEE80211_CHAN_HT40)) {
559 			/* NB: DFS and HT40 don't mix */
560 			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
561 			    "skip HT40 chan, DFS required\n");
562 			continue;
563 		}
564 #endif
565 		/*
566 		 * XXX TODO: handle REG_EXT_FCC_CH_144.
567 		 *
568 		 * Figure out which instances/uses cause us to not
569 		 * be allowed to use channel 144 (pri or sec overlap.)
570 		 */
571 
572 		bfreq_lo = MAX(fband->lowChannel + low_adj, freq_lo);
573 		bfreq_hi = MIN(fband->highChannel + hi_adj, freq_hi);
574 
575 		/*
576 		 * Don't start the 5GHz channel list at 5120MHz.
577 		 *
578 		 * Unfortunately (sigh) the HT40 channel creation
579 		 * logic will create HT40U channels at 5120, 5160, 5200.
580 		 * This means that 36 (5180) isn't considered as a
581 		 * HT40 channel, and everything goes messed up from there.
582 		 */
583 		if ((cm->flags & IEEE80211_CHAN_5GHZ) &&
584 		    (cm->flags & IEEE80211_CHAN_HT40U)) {
585 			if (bfreq_lo < 5180)
586 				bfreq_lo = 5180;
587 		}
588 
589 		/*
590 		 * Same with HT40D - need to start at 5200 or the low
591 		 * channels are all wrong again.
592 		 */
593 		if ((cm->flags & IEEE80211_CHAN_5GHZ) &&
594 		    (cm->flags & IEEE80211_CHAN_HT40D)) {
595 			if (bfreq_lo < 5200)
596 				bfreq_lo = 5200;
597 		}
598 
599 		if (fband->channelSep >= channelSep)
600 			step = fband->channelSep;
601 		else
602 			step = roundup(channelSep, fband->channelSep);
603 
604 		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
605 		    "%s: freq_lo=%d, freq_hi=%d, low_adj=%d, hi_adj=%d, "
606 		    "bandlo=%d, bandhi=%d, bfreqlo=%d, bfreqhi=%d, step=%d, "
607 		    "flags=0x%08x\n",
608 		    __func__,
609 		    (int) freq_lo,
610 		    (int) freq_hi,
611 		    (int) low_adj,
612 		    (int) hi_adj,
613 		    (int) fband->lowChannel,
614 		    (int) fband->highChannel,
615 		    (int) bfreq_lo,
616 		    (int) bfreq_hi,
617 		    step,
618 		    (int) cm->flags);
619 
620 		error = add_chanlist_band(ah, chans, maxchans, nchans,
621 		    bfreq_lo, bfreq_hi, step, cm->flags, fband, rd);
622 		if (error != 0)	{
623 			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
624 			    "%s: too many channels for channel table\n",
625 			    __func__);
626 			return;
627 		}
628 	}
629 }
630 
631 static u_int
632 getmodesmask(struct ath_hal *ah, REG_DOMAIN *rd5GHz, u_int modeSelect)
633 {
634 #define	HAL_MODE_11A_ALL \
635 	(HAL_MODE_11A | HAL_MODE_11A_TURBO | HAL_MODE_TURBO | \
636 	 HAL_MODE_11A_QUARTER_RATE | HAL_MODE_11A_HALF_RATE)
637 	u_int modesMask;
638 
639 	/* get modes that HW is capable of */
640 	modesMask = ath_hal_getWirelessModes(ah);
641 	modesMask &= modeSelect;
642 	/* optimize work below if no 11a channels */
643 	if (isChanBitMaskZero(rd5GHz->chan11a) &&
644 	    (modesMask & HAL_MODE_11A_ALL)) {
645 		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
646 		    "%s: disallow all 11a\n", __func__);
647 		modesMask &= ~HAL_MODE_11A_ALL;
648 	}
649 
650 	return (modesMask);
651 #undef HAL_MODE_11A_ALL
652 }
653 
654 /*
655  * Construct the channel list for the specified regulatory config.
656  */
657 static HAL_STATUS
658 getchannels(struct ath_hal *ah,
659     struct ieee80211_channel chans[], u_int maxchans, int *nchans,
660     u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
661     HAL_BOOL enableExtendedChannels,
662     COUNTRY_CODE_TO_ENUM_RD **pcountry,
663     REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz)
664 {
665 	REG_DOMAIN *rd5GHz, *rd2GHz;
666 	u_int modesMask;
667 	const struct cmode *cm;
668 	HAL_STATUS status;
669 
670 	HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u regDmn 0x%x mode 0x%x%s\n",
671 	    __func__, cc, regDmn, modeSelect,
672 	    enableExtendedChannels ? " ecm" : "");
673 
674 	status = getregstate(ah, cc, regDmn, pcountry, &rd2GHz, &rd5GHz);
675 	if (status != HAL_OK)
676 		return status;
677 
678 	modesMask = getmodesmask(ah, rd5GHz, modeSelect);
679 	/* XXX error? */
680 	if (modesMask == 0)
681 		goto done;
682 
683 	for (cm = modes; cm < &modes[N(modes)]; cm++) {
684 		REG_DOMAIN *rd;
685 
686 		if ((cm->mode & modesMask) == 0) {
687 			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
688 			    "%s: skip mode 0x%x flags 0x%x\n",
689 			    __func__, cm->mode, cm->flags);
690 			continue;
691 		}
692 
693 		if (cm->flags & IEEE80211_CHAN_5GHZ)
694 			rd = rd5GHz;
695 		else if (cm->flags & IEEE80211_CHAN_2GHZ)
696 			rd = rd2GHz;
697 		else {
698 			ath_hal_printf(ah, "%s: Unknown HAL flags 0x%x\n",
699 			    __func__, cm->flags);
700 			return HAL_EINVAL;
701 		}
702 
703 		add_chanlist_mode(ah, chans, maxchans, nchans, cm,
704 		    rd, enableExtendedChannels);
705 		if (*nchans >= maxchans)
706 			goto done;
707 	}
708 done:
709 	/* NB: pcountry set above by getregstate */
710 	if (prd2GHz != AH_NULL)
711 		*prd2GHz = rd2GHz;
712 	if (prd5GHz != AH_NULL)
713 		*prd5GHz = rd5GHz;
714 	return HAL_OK;
715 }
716 
717 /*
718  * Retrieve a channel list without affecting runtime state.
719  */
720 HAL_STATUS
721 ath_hal_getchannels(struct ath_hal *ah,
722     struct ieee80211_channel chans[], u_int maxchans, int *nchans,
723     u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
724     HAL_BOOL enableExtendedChannels)
725 {
726 	return getchannels(ah, chans, maxchans, nchans, modeSelect,
727 	    cc, regDmn, enableExtendedChannels, AH_NULL, AH_NULL, AH_NULL);
728 }
729 
730 /*
731  * Handle frequency mapping from 900Mhz range to 2.4GHz range
732  * for GSM radios.  This is done when we need the h/w frequency
733  * and the channel is marked IEEE80211_CHAN_GSM.
734  */
735 static int
736 ath_hal_mapgsm(int sku, int freq)
737 {
738 	if (sku == SKU_XR9)
739 		return 1520 + freq;
740 	if (sku == SKU_GZ901)
741 		return 1544 + freq;
742 	if (sku == SKU_SR9)
743 		return 3344 - freq;
744 	if (sku == SKU_XC900M)
745 		return 1517 + freq;
746 	HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
747 	    "%s: cannot map freq %u unknown gsm sku %u\n",
748 	    __func__, freq, sku);
749 	return freq;
750 }
751 
752 /*
753  * Setup the internal/private channel state given a table of
754  * net80211 channels.  We collapse entries for the same frequency
755  * and record the frequency for doing noise floor processing
756  * where we don't have net80211 channel context.
757  */
758 static HAL_BOOL
759 assignPrivateChannels(struct ath_hal *ah,
760 	struct ieee80211_channel chans[], int nchans, int sku)
761 {
762 	HAL_CHANNEL_INTERNAL *ic;
763 	int i, j, next, freq;
764 
765 	next = 0;
766 	for (i = 0; i < nchans; i++) {
767 		struct ieee80211_channel *c = &chans[i];
768 		for (j = i-1; j >= 0; j--)
769 			if (chans[j].ic_freq == c->ic_freq) {
770 				c->ic_devdata = chans[j].ic_devdata;
771 				break;
772 			}
773 		if (j < 0) {
774 			/* new entry, assign a private channel entry */
775 			if (next >= N(AH_PRIVATE(ah)->ah_channels)) {
776 				HALDEBUG(ah, HAL_DEBUG_ANY,
777 				    "%s: too many channels, max %zu\n",
778 				    __func__, N(AH_PRIVATE(ah)->ah_channels));
779 				return AH_FALSE;
780 			}
781 			/*
782 			 * Handle frequency mapping for 900MHz devices.
783 			 * The hardware uses 2.4GHz frequencies that are
784 			 * down-converted.  The 802.11 layer uses the
785 			 * true frequencies.
786 			 */
787 			freq = IEEE80211_IS_CHAN_GSM(c) ?
788 			    ath_hal_mapgsm(sku, c->ic_freq) : c->ic_freq;
789 
790 			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
791 			    "%s: private[%3u] %u/0x%x -> channel %u\n",
792 			    __func__, next, c->ic_freq, c->ic_flags, freq);
793 
794 			ic = &AH_PRIVATE(ah)->ah_channels[next];
795 			/*
796 			 * NB: This clears privFlags which means ancillary
797 			 *     code like ANI and IQ calibration will be
798 			 *     restarted and re-setup any per-channel state.
799 			 */
800 			OS_MEMZERO(ic, sizeof(*ic));
801 			ic->channel = freq;
802 			c->ic_devdata = next;
803 			next++;
804 		}
805 	}
806 	AH_PRIVATE(ah)->ah_nchan = next;
807 	HALDEBUG(ah, HAL_DEBUG_ANY, "%s: %u public, %u private channels\n",
808 	    __func__, nchans, next);
809 	return AH_TRUE;
810 }
811 
812 /*
813  * Setup the channel list based on the information in the EEPROM.
814  */
815 HAL_STATUS
816 ath_hal_init_channels(struct ath_hal *ah,
817     struct ieee80211_channel chans[], u_int maxchans, int *nchans,
818     u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
819     HAL_BOOL enableExtendedChannels)
820 {
821 	COUNTRY_CODE_TO_ENUM_RD *country;
822 	REG_DOMAIN *rd5GHz, *rd2GHz;
823 	HAL_STATUS status;
824 
825 	status = getchannels(ah, chans, maxchans, nchans, modeSelect,
826 	    cc, regDmn, enableExtendedChannels, &country, &rd2GHz, &rd5GHz);
827 	if (status == HAL_OK &&
828 	    assignPrivateChannels(ah, chans, *nchans, AH_PRIVATE(ah)->ah_currentRD)) {
829 		AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz;
830 		AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz;
831 
832 		ah->ah_countryCode = country->countryCode;
833 		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n",
834 		    __func__, ah->ah_countryCode);
835 
836 		/* Update current DFS domain */
837 		ath_hal_update_dfsdomain(ah);
838 	} else
839 		status = HAL_EINVAL;
840 
841 	return status;
842 }
843 
844 /*
845  * Set the channel list.
846  */
847 HAL_STATUS
848 ath_hal_set_channels(struct ath_hal *ah,
849     struct ieee80211_channel chans[], int nchans,
850     HAL_CTRY_CODE cc, HAL_REG_DOMAIN rd)
851 {
852 	COUNTRY_CODE_TO_ENUM_RD *country;
853 	REG_DOMAIN *rd5GHz, *rd2GHz;
854 	HAL_STATUS status;
855 
856 	switch (rd) {
857 	case SKU_SR9:
858 	case SKU_XR9:
859 	case SKU_GZ901:
860 	case SKU_XC900M:
861 		/*
862 		 * Map 900MHz sku's.  The frequencies will be mapped
863 		 * according to the sku to compensate for the down-converter.
864 		 * We use the FCC for these sku's as the mapped channel
865 		 * list is known compatible (will need to change if/when
866 		 * vendors do different mapping in different locales).
867 		 */
868 		status = getregstate(ah, CTRY_DEFAULT, SKU_FCC,
869 		    &country, &rd2GHz, &rd5GHz);
870 		break;
871 	default:
872 		status = getregstate(ah, cc, rd,
873 		    &country, &rd2GHz, &rd5GHz);
874 		rd = AH_PRIVATE(ah)->ah_currentRD;
875 		break;
876 	}
877 	if (status == HAL_OK && assignPrivateChannels(ah, chans, nchans, rd)) {
878 		AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz;
879 		AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz;
880 
881 		ah->ah_countryCode = country->countryCode;
882 		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n",
883 		    __func__, ah->ah_countryCode);
884 	} else
885 		status = HAL_EINVAL;
886 
887 	if (status == HAL_OK) {
888 		/* Update current DFS domain */
889 		(void) ath_hal_update_dfsdomain(ah);
890 	}
891 	return status;
892 }
893 
894 #ifdef AH_DEBUG
895 /*
896  * Return the internal channel corresponding to a public channel.
897  * NB: normally this routine is inline'd (see ah_internal.h)
898  */
899 HAL_CHANNEL_INTERNAL *
900 ath_hal_checkchannel(struct ath_hal *ah, const struct ieee80211_channel *c)
901 {
902 	HAL_CHANNEL_INTERNAL *cc = &AH_PRIVATE(ah)->ah_channels[c->ic_devdata];
903 
904 	if (c->ic_devdata < AH_PRIVATE(ah)->ah_nchan &&
905 	    (c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c)))
906 		return cc;
907 	if (c->ic_devdata >= AH_PRIVATE(ah)->ah_nchan) {
908 		HALDEBUG(ah, HAL_DEBUG_ANY,
909 		    "%s: bad mapping, devdata %u nchans %u\n",
910 		   __func__, c->ic_devdata, AH_PRIVATE(ah)->ah_nchan);
911 		HALASSERT(c->ic_devdata < AH_PRIVATE(ah)->ah_nchan);
912 	} else {
913 		HALDEBUG(ah, HAL_DEBUG_ANY,
914 		    "%s: no match for %u/0x%x devdata %u channel %u\n",
915 		   __func__, c->ic_freq, c->ic_flags, c->ic_devdata,
916 		   cc->channel);
917 		HALASSERT(c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c));
918 	}
919 	return AH_NULL;
920 }
921 #endif /* AH_DEBUG */
922 
923 #define isWwrSKU(_ah) \
924 	((getEepromRD((_ah)) & WORLD_SKU_MASK) == WORLD_SKU_PREFIX || \
925 	  getEepromRD(_ah) == WORLD)
926 
927 /*
928  * Return the test group for the specific channel based on
929  * the current regulatory setup.
930  */
931 u_int
932 ath_hal_getctl(struct ath_hal *ah, const struct ieee80211_channel *c)
933 {
934 	u_int ctl;
935 
936 	if (AH_PRIVATE(ah)->ah_rd2GHz == AH_PRIVATE(ah)->ah_rd5GHz ||
937 	    (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)))
938 		ctl = SD_NO_CTL;
939 	else if (IEEE80211_IS_CHAN_2GHZ(c))
940 		ctl = AH_PRIVATE(ah)->ah_rd2GHz->conformanceTestLimit;
941 	else
942 		ctl = AH_PRIVATE(ah)->ah_rd5GHz->conformanceTestLimit;
943 	if (IEEE80211_IS_CHAN_B(c))
944 		return ctl | CTL_11B;
945 	if (IEEE80211_IS_CHAN_G(c))
946 		return ctl | CTL_11G;
947 	if (IEEE80211_IS_CHAN_108G(c))
948 		return ctl | CTL_108G;
949 	if (IEEE80211_IS_CHAN_TURBO(c))
950 		return ctl | CTL_TURBO;
951 	if (IEEE80211_IS_CHAN_A(c))
952 		return ctl | CTL_11A;
953 	return ctl;
954 }
955 
956 /*
957  * Update the current dfsDomain setting based on the given
958  * country code.
959  *
960  * Since FreeBSD/net80211 allows the channel set to change
961  * after the card has been setup (via ath_hal_init_channels())
962  * this function method is needed to update ah_dfsDomain.
963  */
964 void
965 ath_hal_update_dfsdomain(struct ath_hal *ah)
966 {
967 	const REG_DOMAIN *rd5GHz = AH_PRIVATE(ah)->ah_rd5GHz;
968 	HAL_DFS_DOMAIN dfsDomain = HAL_DFS_UNINIT_DOMAIN;
969 
970 	if (rd5GHz->dfsMask & DFS_FCC3)
971 		dfsDomain = HAL_DFS_FCC_DOMAIN;
972 	if (rd5GHz->dfsMask & DFS_ETSI)
973 		dfsDomain = HAL_DFS_ETSI_DOMAIN;
974 	if (rd5GHz->dfsMask & DFS_MKK4)
975 		dfsDomain = HAL_DFS_MKK4_DOMAIN;
976 	AH_PRIVATE(ah)->ah_dfsDomain = dfsDomain;
977 	HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s ah_dfsDomain: %d\n",
978 	    __func__, AH_PRIVATE(ah)->ah_dfsDomain);
979 }
980 
981 /*
982  * Return the max allowed antenna gain and apply any regulatory
983  * domain specific changes.
984  *
985  * NOTE: a negative reduction is possible in RD's that only
986  * measure radiated power (e.g., ETSI) which would increase
987  * that actual conducted output power (though never beyond
988  * the calibrated target power).
989  */
990 u_int
991 ath_hal_getantennareduction(struct ath_hal *ah,
992     const struct ieee80211_channel *chan, u_int twiceGain)
993 {
994 	int8_t antennaMax = twiceGain - chan->ic_maxantgain*2;
995 	return (antennaMax < 0) ? 0 : antennaMax;
996 }
997