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