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