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
101static 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
128static void ath_hal_update_dfsdomain(struct ath_hal *ah);
129
130static OS_INLINE uint16_t
131getEepromRD(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 */
139static HAL_BOOL
140isChanBitMaskZero(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 */
156static HAL_BOOL
157isEepromValid(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 */
181static COUNTRY_CODE_TO_ENUM_RD*
182findCountry(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
193static REG_DOMAIN *
194findRegDmn(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
205static REG_DMN_PAIR_MAPPING *
206findRegDmnPair(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 */
222static HAL_CTRY_CODE
223getDefaultCountry(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
243static HAL_BOOL
244IS_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
255static HAL_STATUS
256getregstate(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 */
359static HAL_STATUS
360getchannels(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	}
576done:
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 */
592HAL_STATUS
593ath_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 */
607static int
608ath_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 */
630static HAL_BOOL
631assignPrivateChannels(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 */
687HAL_STATUS
688ath_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 */
719HAL_STATUS
720ath_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 */
771HAL_CHANNEL_INTERNAL *
772ath_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 */
803u_int
804ath_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 */
837void
838ath_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 */
864u_int
865ath_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