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