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