ah_regdomain.c revision 224242
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: head/sys/dev/ath/ath_hal/ah_regdomain.c 224242 2011-07-21 08:31:55Z adrian $
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 OS_INLINE uint16_t
129getEepromRD(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 */
137static HAL_BOOL
138isChanBitMaskZero(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 */
154static HAL_BOOL
155isEepromValid(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_G(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 */
179static COUNTRY_CODE_TO_ENUM_RD*
180findCountry(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
191static REG_DOMAIN *
192findRegDmn(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
203static REG_DMN_PAIR_MAPPING *
204findRegDmnPair(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 */
220static HAL_CTRY_CODE
221getDefaultCountry(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
241static HAL_BOOL
242IS_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
253static HAL_STATUS
254getregstate(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 */
357static HAL_STATUS
358getchannels(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 0
530				if ((fband->useDfs & dfsMask) &&
531				    (cm->flags & IEEE80211_CHAN_HT40)) {
532					/* NB: DFS and HT40 don't mix */
533					HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
534					    "skip HT40 chan, DFS required\n");
535					continue;
536				}
537#endif
538				/*
539				 * Make sure that channel separation
540				 * meets the requirement.
541				 */
542				if (lastc && channelSep &&
543				    (c-lastc) < channelSep)
544					continue;
545				lastc = c;
546
547				OS_MEMZERO(ic, sizeof(*ic));
548				ic->ic_freq = c;
549				ic->ic_flags = cm->flags;
550				ic->ic_maxregpower = fband->powerDfs;
551				ath_hal_getpowerlimits(ah, ic);
552				ic->ic_maxantgain = fband->antennaMax;
553				if (fband->usePassScan & pscan)
554					ic->ic_flags |= IEEE80211_CHAN_PASSIVE;
555				if (fband->useDfs & dfsMask)
556					ic->ic_flags |= IEEE80211_CHAN_DFS;
557				if (IEEE80211_IS_CHAN_5GHZ(ic) &&
558				    (rdflags & DISALLOW_ADHOC_11A))
559					ic->ic_flags |= IEEE80211_CHAN_NOADHOC;
560				if (IEEE80211_IS_CHAN_TURBO(ic) &&
561				    (rdflags & DISALLOW_ADHOC_11A_TURB))
562					ic->ic_flags |= IEEE80211_CHAN_NOADHOC;
563				if (rdflags & NO_HOSTAP)
564					ic->ic_flags |= IEEE80211_CHAN_NOHOSTAP;
565				if (rdflags & LIMIT_FRAME_4MS)
566					ic->ic_flags |= IEEE80211_CHAN_4MSXMIT;
567				if (rdflags & NEED_NFC)
568					ic->ic_flags |= CHANNEL_NFCREQUIRED;
569
570				ic++, next++;
571			}
572		}
573	}
574done:
575	*nchans = next;
576	/* NB: pcountry set above by getregstate */
577	if (prd2GHz != AH_NULL)
578		*prd2GHz = rd2GHz;
579	if (prd5GHz != AH_NULL)
580		*prd5GHz = rd5GHz;
581	return HAL_OK;
582#undef HAL_MODE_11A_ALL
583#undef CHANNEL_HALF_BW
584#undef CHANNEL_QUARTER_BW
585}
586
587/*
588 * Retrieve a channel list without affecting runtime state.
589 */
590HAL_STATUS
591ath_hal_getchannels(struct ath_hal *ah,
592    struct ieee80211_channel chans[], u_int maxchans, int *nchans,
593    u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
594    HAL_BOOL enableExtendedChannels)
595{
596	return getchannels(ah, chans, maxchans, nchans, modeSelect,
597	    cc, regDmn, enableExtendedChannels, AH_NULL, AH_NULL, AH_NULL);
598}
599
600/*
601 * Handle frequency mapping from 900Mhz range to 2.4GHz range
602 * for GSM radios.  This is done when we need the h/w frequency
603 * and the channel is marked IEEE80211_CHAN_GSM.
604 */
605static int
606ath_hal_mapgsm(int sku, int freq)
607{
608	if (sku == SKU_XR9)
609		return 1520 + freq;
610	if (sku == SKU_GZ901)
611		return 1544 + freq;
612	if (sku == SKU_SR9)
613		return 3344 - freq;
614	HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY,
615	    "%s: cannot map freq %u unknown gsm sku %u\n",
616	    __func__, freq, sku);
617	return freq;
618}
619
620/*
621 * Setup the internal/private channel state given a table of
622 * net80211 channels.  We collapse entries for the same frequency
623 * and record the frequency for doing noise floor processing
624 * where we don't have net80211 channel context.
625 */
626static HAL_BOOL
627assignPrivateChannels(struct ath_hal *ah,
628	struct ieee80211_channel chans[], int nchans, int sku)
629{
630	HAL_CHANNEL_INTERNAL *ic;
631	int i, j, next, freq;
632
633	next = 0;
634	for (i = 0; i < nchans; i++) {
635		struct ieee80211_channel *c = &chans[i];
636		for (j = i-1; j >= 0; j--)
637			if (chans[j].ic_freq == c->ic_freq) {
638				c->ic_devdata = chans[j].ic_devdata;
639				break;
640			}
641		if (j < 0) {
642			/* new entry, assign a private channel entry */
643			if (next >= N(AH_PRIVATE(ah)->ah_channels)) {
644				HALDEBUG(ah, HAL_DEBUG_ANY,
645				    "%s: too many channels, max %zu\n",
646				    __func__, N(AH_PRIVATE(ah)->ah_channels));
647				return AH_FALSE;
648			}
649			/*
650			 * Handle frequency mapping for 900MHz devices.
651			 * The hardware uses 2.4GHz frequencies that are
652			 * down-converted.  The 802.11 layer uses the
653			 * true frequencies.
654			 */
655			freq = IEEE80211_IS_CHAN_GSM(c) ?
656			    ath_hal_mapgsm(sku, c->ic_freq) : c->ic_freq;
657
658			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
659			    "%s: private[%3u] %u/0x%x -> channel %u\n",
660			    __func__, next, c->ic_freq, c->ic_flags, freq);
661
662			ic = &AH_PRIVATE(ah)->ah_channels[next];
663			/*
664			 * NB: This clears privFlags which means ancillary
665			 *     code like ANI and IQ calibration will be
666			 *     restarted and re-setup any per-channel state.
667			 */
668			OS_MEMZERO(ic, sizeof(*ic));
669			ic->channel = freq;
670			c->ic_devdata = next;
671			next++;
672		}
673	}
674	AH_PRIVATE(ah)->ah_nchan = next;
675	HALDEBUG(ah, HAL_DEBUG_ANY, "%s: %u public, %u private channels\n",
676	    __func__, nchans, next);
677	return AH_TRUE;
678}
679
680/*
681 * Setup the channel list based on the information in the EEPROM.
682 */
683HAL_STATUS
684ath_hal_init_channels(struct ath_hal *ah,
685    struct ieee80211_channel chans[], u_int maxchans, int *nchans,
686    u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
687    HAL_BOOL enableExtendedChannels)
688{
689	COUNTRY_CODE_TO_ENUM_RD *country;
690	REG_DOMAIN *rd5GHz, *rd2GHz;
691	HAL_STATUS status;
692
693	status = getchannels(ah, chans, maxchans, nchans, modeSelect,
694	    cc, regDmn, enableExtendedChannels, &country, &rd2GHz, &rd5GHz);
695	if (status == HAL_OK &&
696	    assignPrivateChannels(ah, chans, *nchans, AH_PRIVATE(ah)->ah_currentRD)) {
697		AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz;
698		AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz;
699
700		ah->ah_countryCode = country->countryCode;
701		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n",
702		    __func__, ah->ah_countryCode);
703	} else
704		status = HAL_EINVAL;
705	return status;
706}
707
708/*
709 * Set the channel list.
710 */
711HAL_STATUS
712ath_hal_set_channels(struct ath_hal *ah,
713    struct ieee80211_channel chans[], int nchans,
714    HAL_CTRY_CODE cc, HAL_REG_DOMAIN rd)
715{
716	COUNTRY_CODE_TO_ENUM_RD *country;
717	REG_DOMAIN *rd5GHz, *rd2GHz;
718	HAL_STATUS status;
719
720	switch (rd) {
721	case SKU_SR9:
722	case SKU_XR9:
723	case SKU_GZ901:
724		/*
725		 * Map 900MHz sku's.  The frequencies will be mapped
726		 * according to the sku to compensate for the down-converter.
727		 * We use the FCC for these sku's as the mapped channel
728		 * list is known compatible (will need to change if/when
729		 * vendors do different mapping in different locales).
730		 */
731		status = getregstate(ah, CTRY_DEFAULT, SKU_FCC,
732		    &country, &rd2GHz, &rd5GHz);
733		break;
734	default:
735		status = getregstate(ah, cc, rd,
736		    &country, &rd2GHz, &rd5GHz);
737		rd = AH_PRIVATE(ah)->ah_currentRD;
738		break;
739	}
740	if (status == HAL_OK && assignPrivateChannels(ah, chans, nchans, rd)) {
741		AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz;
742		AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz;
743
744		ah->ah_countryCode = country->countryCode;
745		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n",
746		    __func__, ah->ah_countryCode);
747	} else
748		status = HAL_EINVAL;
749	return status;
750}
751
752#ifdef AH_DEBUG
753/*
754 * Return the internal channel corresponding to a public channel.
755 * NB: normally this routine is inline'd (see ah_internal.h)
756 */
757HAL_CHANNEL_INTERNAL *
758ath_hal_checkchannel(struct ath_hal *ah, const struct ieee80211_channel *c)
759{
760	HAL_CHANNEL_INTERNAL *cc = &AH_PRIVATE(ah)->ah_channels[c->ic_devdata];
761
762	if (c->ic_devdata < AH_PRIVATE(ah)->ah_nchan &&
763	    (c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c)))
764		return cc;
765	if (c->ic_devdata >= AH_PRIVATE(ah)->ah_nchan) {
766		HALDEBUG(ah, HAL_DEBUG_ANY,
767		    "%s: bad mapping, devdata %u nchans %u\n",
768		   __func__, c->ic_devdata, AH_PRIVATE(ah)->ah_nchan);
769		HALASSERT(c->ic_devdata < AH_PRIVATE(ah)->ah_nchan);
770	} else {
771		HALDEBUG(ah, HAL_DEBUG_ANY,
772		    "%s: no match for %u/0x%x devdata %u channel %u\n",
773		   __func__, c->ic_freq, c->ic_flags, c->ic_devdata,
774		   cc->channel);
775		HALASSERT(c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c));
776	}
777	return AH_NULL;
778}
779#endif /* AH_DEBUG */
780
781#define isWwrSKU(_ah) \
782	((getEepromRD((_ah)) & WORLD_SKU_MASK) == WORLD_SKU_PREFIX || \
783	  getEepromRD(_ah) == WORLD)
784
785/*
786 * Return the test group for the specific channel based on
787 * the current regulatory setup.
788 */
789u_int
790ath_hal_getctl(struct ath_hal *ah, const struct ieee80211_channel *c)
791{
792	u_int ctl;
793
794	if (AH_PRIVATE(ah)->ah_rd2GHz == AH_PRIVATE(ah)->ah_rd5GHz ||
795	    (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)))
796		ctl = SD_NO_CTL;
797	else if (IEEE80211_IS_CHAN_2GHZ(c))
798		ctl = AH_PRIVATE(ah)->ah_rd2GHz->conformanceTestLimit;
799	else
800		ctl = AH_PRIVATE(ah)->ah_rd5GHz->conformanceTestLimit;
801	if (IEEE80211_IS_CHAN_B(c))
802		return ctl | CTL_11B;
803	if (IEEE80211_IS_CHAN_G(c))
804		return ctl | CTL_11G;
805	if (IEEE80211_IS_CHAN_108G(c))
806		return ctl | CTL_108G;
807	if (IEEE80211_IS_CHAN_TURBO(c))
808		return ctl | CTL_TURBO;
809	if (IEEE80211_IS_CHAN_A(c))
810		return ctl | CTL_11A;
811	return ctl;
812}
813
814/*
815 * Return the max allowed antenna gain and apply any regulatory
816 * domain specific changes.
817 *
818 * NOTE: a negative reduction is possible in RD's that only
819 * measure radiated power (e.g., ETSI) which would increase
820 * that actual conducted output power (though never beyond
821 * the calibrated target power).
822 */
823u_int
824ath_hal_getantennareduction(struct ath_hal *ah,
825    const struct ieee80211_channel *chan, u_int twiceGain)
826{
827	int8_t antennaMax = twiceGain - chan->ic_maxantgain*2;
828	return (antennaMax < 0) ? 0 : antennaMax;
829}
830