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