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