Merge branch 'linus' into x86/tracehook
[deliverable/linux.git] / drivers / net / wireless / ath9k / regd.c
1 /*
2 * Copyright (c) 2008 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <linux/kernel.h>
18 #include <linux/slab.h>
19 #include "core.h"
20 #include "hw.h"
21 #include "regd.h"
22 #include "regd_common.h"
23
24 static int ath9k_regd_chansort(const void *a, const void *b)
25 {
26 const struct ath9k_channel *ca = a;
27 const struct ath9k_channel *cb = b;
28
29 return (ca->channel == cb->channel) ?
30 (ca->channelFlags & CHAN_FLAGS) -
31 (cb->channelFlags & CHAN_FLAGS) : ca->channel - cb->channel;
32 }
33
34 static void
35 ath9k_regd_sort(void *a, u32 n, u32 size, ath_hal_cmp_t *cmp)
36 {
37 u8 *aa = a;
38 u8 *ai, *t;
39
40 for (ai = aa + size; --n >= 1; ai += size)
41 for (t = ai; t > aa; t -= size) {
42 u8 *u = t - size;
43 if (cmp(u, t) <= 0)
44 break;
45 swap(u, t, size);
46 }
47 }
48
49 static u16 ath9k_regd_get_eepromRD(struct ath_hal *ah)
50 {
51 return ah->ah_currentRD & ~WORLDWIDE_ROAMING_FLAG;
52 }
53
54 static bool ath9k_regd_is_chan_bm_zero(u64 *bitmask)
55 {
56 int i;
57
58 for (i = 0; i < BMLEN; i++) {
59 if (bitmask[i] != 0)
60 return false;
61 }
62 return true;
63 }
64
65 static bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah)
66 {
67 u16 rd = ath9k_regd_get_eepromRD(ah);
68 int i;
69
70 if (rd & COUNTRY_ERD_FLAG) {
71 u16 cc = rd & ~COUNTRY_ERD_FLAG;
72 for (i = 0; i < ARRAY_SIZE(allCountries); i++)
73 if (allCountries[i].countryCode == cc)
74 return true;
75 } else {
76 for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
77 if (regDomainPairs[i].regDmnEnum == rd)
78 return true;
79 }
80 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
81 "%s: invalid regulatory domain/country code 0x%x\n",
82 __func__, rd);
83 return false;
84 }
85
86 static bool ath9k_regd_is_fcc_midband_supported(struct ath_hal *ah)
87 {
88 u32 regcap;
89
90 regcap = ah->ah_caps.reg_cap;
91
92 if (regcap & AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND)
93 return true;
94 else
95 return false;
96 }
97
98 static bool ath9k_regd_is_ccode_valid(struct ath_hal *ah,
99 u16 cc)
100 {
101 u16 rd;
102 int i;
103
104 if (cc == CTRY_DEFAULT)
105 return true;
106 if (cc == CTRY_DEBUG)
107 return true;
108
109 rd = ath9k_regd_get_eepromRD(ah);
110 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: EEPROM regdomain 0x%x\n",
111 __func__, rd);
112
113 if (rd & COUNTRY_ERD_FLAG) {
114 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
115 "%s: EEPROM setting is country code %u\n",
116 __func__, rd & ~COUNTRY_ERD_FLAG);
117 return cc == (rd & ~COUNTRY_ERD_FLAG);
118 }
119
120 for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
121 if (cc == allCountries[i].countryCode) {
122 #ifdef AH_SUPPORT_11D
123 if ((rd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)
124 return true;
125 #endif
126 if (allCountries[i].regDmnEnum == rd ||
127 rd == DEBUG_REG_DMN || rd == NO_ENUMRD)
128 return true;
129 }
130 }
131 return false;
132 }
133
134 static void
135 ath9k_regd_get_wmodes_nreg(struct ath_hal *ah,
136 struct country_code_to_enum_rd *country,
137 struct regDomain *rd5GHz,
138 unsigned long *modes_allowed)
139 {
140 bitmap_copy(modes_allowed, ah->ah_caps.wireless_modes, ATH9K_MODE_MAX);
141
142 if (test_bit(ATH9K_MODE_11G, ah->ah_caps.wireless_modes) &&
143 (!country->allow11g))
144 clear_bit(ATH9K_MODE_11G, modes_allowed);
145
146 if (test_bit(ATH9K_MODE_11A, ah->ah_caps.wireless_modes) &&
147 (ath9k_regd_is_chan_bm_zero(rd5GHz->chan11a)))
148 clear_bit(ATH9K_MODE_11A, modes_allowed);
149
150 if (test_bit(ATH9K_MODE_11NG_HT20, ah->ah_caps.wireless_modes)
151 && (!country->allow11ng20))
152 clear_bit(ATH9K_MODE_11NG_HT20, modes_allowed);
153
154 if (test_bit(ATH9K_MODE_11NA_HT20, ah->ah_caps.wireless_modes)
155 && (!country->allow11na20))
156 clear_bit(ATH9K_MODE_11NA_HT20, modes_allowed);
157
158 if (test_bit(ATH9K_MODE_11NG_HT40PLUS, ah->ah_caps.wireless_modes) &&
159 (!country->allow11ng40))
160 clear_bit(ATH9K_MODE_11NG_HT40PLUS, modes_allowed);
161
162 if (test_bit(ATH9K_MODE_11NG_HT40MINUS, ah->ah_caps.wireless_modes) &&
163 (!country->allow11ng40))
164 clear_bit(ATH9K_MODE_11NG_HT40MINUS, modes_allowed);
165
166 if (test_bit(ATH9K_MODE_11NA_HT40PLUS, ah->ah_caps.wireless_modes) &&
167 (!country->allow11na40))
168 clear_bit(ATH9K_MODE_11NA_HT40PLUS, modes_allowed);
169
170 if (test_bit(ATH9K_MODE_11NA_HT40MINUS, ah->ah_caps.wireless_modes) &&
171 (!country->allow11na40))
172 clear_bit(ATH9K_MODE_11NA_HT40MINUS, modes_allowed);
173 }
174
175 bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah)
176 {
177 u16 rd;
178
179 rd = ath9k_regd_get_eepromRD(ah);
180
181 switch (rd) {
182 case FCC4_FCCA:
183 case (CTRY_UNITED_STATES_FCC49 | COUNTRY_ERD_FLAG):
184 return true;
185 case DEBUG_REG_DMN:
186 case NO_ENUMRD:
187 if (ah->ah_countryCode == CTRY_UNITED_STATES_FCC49)
188 return true;
189 break;
190 }
191 return false;
192 }
193
194 static struct country_code_to_enum_rd*
195 ath9k_regd_find_country(u16 countryCode)
196 {
197 int i;
198
199 for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
200 if (allCountries[i].countryCode == countryCode)
201 return &allCountries[i];
202 }
203 return NULL;
204 }
205
206 static u16 ath9k_regd_get_default_country(struct ath_hal *ah)
207 {
208 u16 rd;
209 int i;
210
211 rd = ath9k_regd_get_eepromRD(ah);
212 if (rd & COUNTRY_ERD_FLAG) {
213 struct country_code_to_enum_rd *country = NULL;
214 u16 cc = rd & ~COUNTRY_ERD_FLAG;
215
216 country = ath9k_regd_find_country(cc);
217 if (country != NULL)
218 return cc;
219 }
220
221 for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
222 if (regDomainPairs[i].regDmnEnum == rd) {
223 if (regDomainPairs[i].singleCC != 0)
224 return regDomainPairs[i].singleCC;
225 else
226 i = ARRAY_SIZE(regDomainPairs);
227 }
228 return CTRY_DEFAULT;
229 }
230
231 static bool ath9k_regd_is_valid_reg_domain(int regDmn,
232 struct regDomain *rd)
233 {
234 int i;
235
236 for (i = 0; i < ARRAY_SIZE(regDomains); i++) {
237 if (regDomains[i].regDmnEnum == regDmn) {
238 if (rd != NULL) {
239 memcpy(rd, &regDomains[i],
240 sizeof(struct regDomain));
241 }
242 return true;
243 }
244 }
245 return false;
246 }
247
248 static bool ath9k_regd_is_valid_reg_domainPair(int regDmnPair)
249 {
250 int i;
251
252 if (regDmnPair == NO_ENUMRD)
253 return false;
254 for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
255 if (regDomainPairs[i].regDmnEnum == regDmnPair)
256 return true;
257 }
258 return false;
259 }
260
261 static bool
262 ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn,
263 u16 channelFlag, struct regDomain *rd)
264 {
265 int i, found;
266 u64 flags = NO_REQ;
267 struct reg_dmn_pair_mapping *regPair = NULL;
268 int regOrg;
269
270 regOrg = regDmn;
271 if (regDmn == CTRY_DEFAULT) {
272 u16 rdnum;
273 rdnum = ath9k_regd_get_eepromRD(ah);
274
275 if (!(rdnum & COUNTRY_ERD_FLAG)) {
276 if (ath9k_regd_is_valid_reg_domain(rdnum, NULL) ||
277 ath9k_regd_is_valid_reg_domainPair(rdnum)) {
278 regDmn = rdnum;
279 }
280 }
281 }
282
283 if ((regDmn & MULTI_DOMAIN_MASK) == 0) {
284 for (i = 0, found = 0;
285 (i < ARRAY_SIZE(regDomainPairs)) && (!found); i++) {
286 if (regDomainPairs[i].regDmnEnum == regDmn) {
287 regPair = &regDomainPairs[i];
288 found = 1;
289 }
290 }
291 if (!found) {
292 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
293 "%s: Failed to find reg domain pair %u\n",
294 __func__, regDmn);
295 return false;
296 }
297 if (!(channelFlag & CHANNEL_2GHZ)) {
298 regDmn = regPair->regDmn5GHz;
299 flags = regPair->flags5GHz;
300 }
301 if (channelFlag & CHANNEL_2GHZ) {
302 regDmn = regPair->regDmn2GHz;
303 flags = regPair->flags2GHz;
304 }
305 }
306
307 found = ath9k_regd_is_valid_reg_domain(regDmn, rd);
308 if (!found) {
309 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
310 "%s: Failed to find unitary reg domain %u\n",
311 __func__, regDmn);
312 return false;
313 } else {
314 rd->pscan &= regPair->pscanMask;
315 if (((regOrg & MULTI_DOMAIN_MASK) == 0) &&
316 (flags != NO_REQ)) {
317 rd->flags = flags;
318 }
319
320 rd->flags &= (channelFlag & CHANNEL_2GHZ) ?
321 REG_DOMAIN_2GHZ_MASK : REG_DOMAIN_5GHZ_MASK;
322 return true;
323 }
324 }
325
326 static bool ath9k_regd_is_bit_set(int bit, u64 *bitmask)
327 {
328 int byteOffset, bitnum;
329 u64 val;
330
331 byteOffset = bit / 64;
332 bitnum = bit - byteOffset * 64;
333 val = ((u64) 1) << bitnum;
334 if (bitmask[byteOffset] & val)
335 return true;
336 else
337 return false;
338 }
339
340 static void
341 ath9k_regd_add_reg_classid(u8 *regclassids, u32 maxregids,
342 u32 *nregids, u8 regclassid)
343 {
344 int i;
345
346 if (regclassid == 0)
347 return;
348
349 for (i = 0; i < maxregids; i++) {
350 if (regclassids[i] == regclassid)
351 return;
352 if (regclassids[i] == 0)
353 break;
354 }
355
356 if (i == maxregids)
357 return;
358 else {
359 regclassids[i] = regclassid;
360 *nregids += 1;
361 }
362
363 return;
364 }
365
366 static bool
367 ath9k_regd_get_eeprom_reg_ext_bits(struct ath_hal *ah,
368 enum reg_ext_bitmap bit)
369 {
370 return (ah->ah_currentRDExt & (1 << bit)) ? true : false;
371 }
372
373 #ifdef ATH_NF_PER_CHAN
374
375 static void ath9k_regd_init_rf_buffer(struct ath9k_channel *ichans,
376 int nchans)
377 {
378 int i, j, next;
379
380 for (next = 0; next < nchans; next++) {
381 for (i = 0; i < NUM_NF_READINGS; i++) {
382 ichans[next].nfCalHist[i].currIndex = 0;
383 ichans[next].nfCalHist[i].privNF =
384 AR_PHY_CCA_MAX_GOOD_VALUE;
385 ichans[next].nfCalHist[i].invalidNFcount =
386 AR_PHY_CCA_FILTERWINDOW_LENGTH;
387 for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
388 ichans[next].nfCalHist[i].nfCalBuffer[j] =
389 AR_PHY_CCA_MAX_GOOD_VALUE;
390 }
391 }
392 }
393 }
394 #endif
395
396 static int ath9k_regd_is_chan_present(struct ath_hal *ah,
397 u16 c)
398 {
399 int i;
400
401 for (i = 0; i < 150; i++) {
402 if (!ah->ah_channels[i].channel)
403 return -1;
404 else if (ah->ah_channels[i].channel == c)
405 return i;
406 }
407
408 return -1;
409 }
410
411 static bool
412 ath9k_regd_add_channel(struct ath_hal *ah,
413 u16 c,
414 u16 c_lo,
415 u16 c_hi,
416 u16 maxChan,
417 u8 ctl,
418 int pos,
419 struct regDomain rd5GHz,
420 struct RegDmnFreqBand *fband,
421 struct regDomain *rd,
422 const struct cmode *cm,
423 struct ath9k_channel *ichans,
424 bool enableExtendedChannels)
425 {
426 struct ath9k_channel *chan;
427 int ret;
428 u32 channelFlags = 0;
429 u8 privFlags = 0;
430
431 if (!(c_lo <= c && c <= c_hi)) {
432 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
433 "%s: c %u out of range [%u..%u]\n",
434 __func__, c, c_lo, c_hi);
435 return false;
436 }
437 if ((fband->channelBW == CHANNEL_HALF_BW) &&
438 !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_HALFRATE)) {
439 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
440 "%s: Skipping %u half rate channel\n",
441 __func__, c);
442 return false;
443 }
444
445 if ((fband->channelBW == CHANNEL_QUARTER_BW) &&
446 !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_QUARTERRATE)) {
447 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
448 "%s: Skipping %u quarter rate channel\n",
449 __func__, c);
450 return false;
451 }
452
453 if (((c + fband->channelSep) / 2) > (maxChan + HALF_MAXCHANBW)) {
454 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
455 "%s: c %u > maxChan %u\n",
456 __func__, c, maxChan);
457 return false;
458 }
459
460 if ((fband->usePassScan & IS_ECM_CHAN) && !enableExtendedChannels) {
461 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
462 "Skipping ecm channel\n");
463 return false;
464 }
465
466 if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == ATH9K_M_HOSTAP)) {
467 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
468 "Skipping HOSTAP channel\n");
469 return false;
470 }
471
472 if (IS_HT40_MODE(cm->mode) &&
473 !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_FCC_DFS_HT40)) &&
474 (fband->useDfs) &&
475 (rd->conformanceTestLimit != MKK)) {
476 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
477 "Skipping HT40 channel (en_fcc_dfs_ht40 = 0)\n");
478 return false;
479 }
480
481 if (IS_HT40_MODE(cm->mode) &&
482 !(ath9k_regd_get_eeprom_reg_ext_bits(ah,
483 REG_EXT_JAPAN_NONDFS_HT40)) &&
484 !(fband->useDfs) && (rd->conformanceTestLimit == MKK)) {
485 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
486 "Skipping HT40 channel (en_jap_ht40 = 0)\n");
487 return false;
488 }
489
490 if (IS_HT40_MODE(cm->mode) &&
491 !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_JAPAN_DFS_HT40)) &&
492 (fband->useDfs) &&
493 (rd->conformanceTestLimit == MKK)) {
494 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
495 "Skipping HT40 channel (en_jap_dfs_ht40 = 0)\n");
496 return false;
497 }
498
499 /* Calculate channel flags */
500
501 channelFlags = cm->flags;
502
503 switch (fband->channelBW) {
504 case CHANNEL_HALF_BW:
505 channelFlags |= CHANNEL_HALF;
506 break;
507 case CHANNEL_QUARTER_BW:
508 channelFlags |= CHANNEL_QUARTER;
509 break;
510 }
511
512 if (fband->usePassScan & rd->pscan)
513 channelFlags |= CHANNEL_PASSIVE;
514 else
515 channelFlags &= ~CHANNEL_PASSIVE;
516 if (fband->useDfs & rd->dfsMask)
517 privFlags = CHANNEL_DFS;
518 else
519 privFlags = 0;
520 if (rd->flags & LIMIT_FRAME_4MS)
521 privFlags |= CHANNEL_4MS_LIMIT;
522 if (privFlags & CHANNEL_DFS)
523 privFlags |= CHANNEL_DISALLOW_ADHOC;
524 if (rd->flags & ADHOC_PER_11D)
525 privFlags |= CHANNEL_PER_11D_ADHOC;
526
527 if (channelFlags & CHANNEL_PASSIVE) {
528 if ((c < 2412) || (c > 2462)) {
529 if (rd5GHz.regDmnEnum == MKK1 ||
530 rd5GHz.regDmnEnum == MKK2) {
531 u32 regcap = ah->ah_caps.reg_cap;
532 if (!(regcap &
533 (AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
534 AR_EEPROM_EEREGCAP_EN_KK_U2 |
535 AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) &&
536 isUNII1OddChan(c)) {
537 channelFlags &= ~CHANNEL_PASSIVE;
538 } else {
539 privFlags |= CHANNEL_DISALLOW_ADHOC;
540 }
541 } else {
542 privFlags |= CHANNEL_DISALLOW_ADHOC;
543 }
544 }
545 }
546
547 if ((cm->mode == ATH9K_MODE_11A) ||
548 (cm->mode == ATH9K_MODE_11NA_HT20) ||
549 (cm->mode == ATH9K_MODE_11NA_HT40PLUS) ||
550 (cm->mode == ATH9K_MODE_11NA_HT40MINUS)) {
551 if (rd->flags & (ADHOC_NO_11A | DISALLOW_ADHOC_11A))
552 privFlags |= CHANNEL_DISALLOW_ADHOC;
553 }
554
555 /* Fill in channel details */
556
557 ret = ath9k_regd_is_chan_present(ah, c);
558 if (ret == -1) {
559 chan = &ah->ah_channels[pos];
560 chan->channel = c;
561 chan->maxRegTxPower = fband->powerDfs;
562 chan->antennaMax = fband->antennaMax;
563 chan->regDmnFlags = rd->flags;
564 chan->maxTxPower = AR5416_MAX_RATE_POWER;
565 chan->minTxPower = AR5416_MAX_RATE_POWER;
566 chan->channelFlags = channelFlags;
567 chan->privFlags = privFlags;
568 } else {
569 chan = &ah->ah_channels[ret];
570 chan->channelFlags |= channelFlags;
571 chan->privFlags |= privFlags;
572 }
573
574 /* Set CTLs */
575
576 if ((cm->flags & CHANNEL_ALL) == CHANNEL_A)
577 chan->conformanceTestLimit[0] = ctl;
578 else if ((cm->flags & CHANNEL_ALL) == CHANNEL_B)
579 chan->conformanceTestLimit[1] = ctl;
580 else if ((cm->flags & CHANNEL_ALL) == CHANNEL_G)
581 chan->conformanceTestLimit[2] = ctl;
582
583 return (ret == -1) ? true : false;
584 }
585
586 static bool ath9k_regd_japan_check(struct ath_hal *ah,
587 int b,
588 struct regDomain *rd5GHz)
589 {
590 bool skipband = false;
591 int i;
592 u32 regcap;
593
594 for (i = 0; i < ARRAY_SIZE(j_bandcheck); i++) {
595 if (j_bandcheck[i].freqbandbit == b) {
596 regcap = ah->ah_caps.reg_cap;
597 if ((j_bandcheck[i].eepromflagtocheck & regcap) == 0) {
598 skipband = true;
599 } else if ((regcap & AR_EEPROM_EEREGCAP_EN_KK_U2) ||
600 (regcap & AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) {
601 rd5GHz->dfsMask |= DFS_MKK4;
602 rd5GHz->pscan |= PSCAN_MKK3;
603 }
604 break;
605 }
606 }
607
608 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
609 "%s: Skipping %d freq band\n",
610 __func__, j_bandcheck[i].freqbandbit);
611
612 return skipband;
613 }
614
615 bool
616 ath9k_regd_init_channels(struct ath_hal *ah,
617 u32 maxchans,
618 u32 *nchans, u8 *regclassids,
619 u32 maxregids, u32 *nregids, u16 cc,
620 bool enableOutdoor,
621 bool enableExtendedChannels)
622 {
623 u16 maxChan = 7000;
624 struct country_code_to_enum_rd *country = NULL;
625 struct regDomain rd5GHz, rd2GHz;
626 const struct cmode *cm;
627 struct ath9k_channel *ichans = &ah->ah_channels[0];
628 int next = 0, b;
629 u8 ctl;
630 int regdmn;
631 u16 chanSep;
632 unsigned long *modes_avail;
633 DECLARE_BITMAP(modes_allowed, ATH9K_MODE_MAX);
634
635 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: cc %u %s %s\n",
636 __func__, cc,
637 enableOutdoor ? "Enable outdoor" : "",
638 enableExtendedChannels ? "Enable ecm" : "");
639
640 if (!ath9k_regd_is_ccode_valid(ah, cc)) {
641 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
642 "%s: invalid country code %d\n", __func__, cc);
643 return false;
644 }
645
646 if (!ath9k_regd_is_eeprom_valid(ah)) {
647 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
648 "%s: invalid EEPROM contents\n", __func__);
649 return false;
650 }
651
652 ah->ah_countryCode = ath9k_regd_get_default_country(ah);
653
654 if (ah->ah_countryCode == CTRY_DEFAULT) {
655 ah->ah_countryCode = cc & COUNTRY_CODE_MASK;
656 if ((ah->ah_countryCode == CTRY_DEFAULT) &&
657 (ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)) {
658 ah->ah_countryCode = CTRY_UNITED_STATES;
659 }
660 }
661
662 #ifdef AH_SUPPORT_11D
663 if (ah->ah_countryCode == CTRY_DEFAULT) {
664 regdmn = ath9k_regd_get_eepromRD(ah);
665 country = NULL;
666 } else {
667 #endif
668 country = ath9k_regd_find_country(ah->ah_countryCode);
669 if (country == NULL) {
670 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
671 "Country is NULL!!!!, cc= %d\n",
672 ah->ah_countryCode);
673 return false;
674 } else {
675 regdmn = country->regDmnEnum;
676 #ifdef AH_SUPPORT_11D
677 if (((ath9k_regd_get_eepromRD(ah) &
678 WORLD_SKU_MASK) == WORLD_SKU_PREFIX) &&
679 (cc == CTRY_UNITED_STATES)) {
680 if (!isWwrSKU_NoMidband(ah)
681 && ath9k_regd_is_fcc_midband_supported(ah))
682 regdmn = FCC3_FCCA;
683 else
684 regdmn = FCC1_FCCA;
685 }
686 #endif
687 }
688 #ifdef AH_SUPPORT_11D
689 }
690 #endif
691 if (!ath9k_regd_get_wmode_regdomain(ah,
692 regdmn,
693 ~CHANNEL_2GHZ,
694 &rd5GHz)) {
695 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
696 "%s: couldn't find unitary "
697 "5GHz reg domain for country %u\n",
698 __func__, ah->ah_countryCode);
699 return false;
700 }
701 if (!ath9k_regd_get_wmode_regdomain(ah,
702 regdmn,
703 CHANNEL_2GHZ,
704 &rd2GHz)) {
705 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
706 "%s: couldn't find unitary 2GHz "
707 "reg domain for country %u\n",
708 __func__, ah->ah_countryCode);
709 return false;
710 }
711
712 if (!isWwrSKU(ah) && ((rd5GHz.regDmnEnum == FCC1) ||
713 (rd5GHz.regDmnEnum == FCC2))) {
714 if (ath9k_regd_is_fcc_midband_supported(ah)) {
715 if (!ath9k_regd_get_wmode_regdomain(ah,
716 FCC3_FCCA,
717 ~CHANNEL_2GHZ,
718 &rd5GHz)) {
719 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
720 "%s: couldn't find unitary 5GHz "
721 "reg domain for country %u\n",
722 __func__, ah->ah_countryCode);
723 return false;
724 }
725 }
726 }
727
728 if (country == NULL) {
729 modes_avail = ah->ah_caps.wireless_modes;
730 } else {
731 ath9k_regd_get_wmodes_nreg(ah, country, &rd5GHz, modes_allowed);
732 modes_avail = modes_allowed;
733
734 if (!enableOutdoor)
735 maxChan = country->outdoorChanStart;
736 }
737
738 next = 0;
739
740 if (maxchans > ARRAY_SIZE(ah->ah_channels))
741 maxchans = ARRAY_SIZE(ah->ah_channels);
742
743 for (cm = modes; cm < &modes[ARRAY_SIZE(modes)]; cm++) {
744 u16 c, c_hi, c_lo;
745 u64 *channelBM = NULL;
746 struct regDomain *rd = NULL;
747 struct RegDmnFreqBand *fband = NULL, *freqs;
748 int8_t low_adj = 0, hi_adj = 0;
749
750 if (!test_bit(cm->mode, modes_avail)) {
751 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
752 "%s: !avail mode %d flags 0x%x\n",
753 __func__, cm->mode, cm->flags);
754 continue;
755 }
756 if (!ath9k_get_channel_edges(ah, cm->flags, &c_lo, &c_hi)) {
757 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
758 "%s: channels 0x%x not supported "
759 "by hardware\n",
760 __func__, cm->flags);
761 continue;
762 }
763
764 switch (cm->mode) {
765 case ATH9K_MODE_11A:
766 case ATH9K_MODE_11NA_HT20:
767 case ATH9K_MODE_11NA_HT40PLUS:
768 case ATH9K_MODE_11NA_HT40MINUS:
769 rd = &rd5GHz;
770 channelBM = rd->chan11a;
771 freqs = &regDmn5GhzFreq[0];
772 ctl = rd->conformanceTestLimit;
773 break;
774 case ATH9K_MODE_11B:
775 rd = &rd2GHz;
776 channelBM = rd->chan11b;
777 freqs = &regDmn2GhzFreq[0];
778 ctl = rd->conformanceTestLimit | CTL_11B;
779 break;
780 case ATH9K_MODE_11G:
781 case ATH9K_MODE_11NG_HT20:
782 case ATH9K_MODE_11NG_HT40PLUS:
783 case ATH9K_MODE_11NG_HT40MINUS:
784 rd = &rd2GHz;
785 channelBM = rd->chan11g;
786 freqs = &regDmn2Ghz11gFreq[0];
787 ctl = rd->conformanceTestLimit | CTL_11G;
788 break;
789 default:
790 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
791 "%s: Unknown HAL mode 0x%x\n", __func__,
792 cm->mode);
793 continue;
794 }
795
796 if (ath9k_regd_is_chan_bm_zero(channelBM))
797 continue;
798
799 if ((cm->mode == ATH9K_MODE_11NA_HT40PLUS) ||
800 (cm->mode == ATH9K_MODE_11NG_HT40PLUS)) {
801 hi_adj = -20;
802 }
803
804 if ((cm->mode == ATH9K_MODE_11NA_HT40MINUS) ||
805 (cm->mode == ATH9K_MODE_11NG_HT40MINUS)) {
806 low_adj = 20;
807 }
808
809 /* XXX: Add a helper here instead */
810 for (b = 0; b < 64 * BMLEN; b++) {
811 if (ath9k_regd_is_bit_set(b, channelBM)) {
812 fband = &freqs[b];
813 if (rd5GHz.regDmnEnum == MKK1
814 || rd5GHz.regDmnEnum == MKK2) {
815 if (ath9k_regd_japan_check(ah,
816 b,
817 &rd5GHz))
818 continue;
819 }
820
821 ath9k_regd_add_reg_classid(regclassids,
822 maxregids,
823 nregids,
824 fband->
825 regClassId);
826
827 if (IS_HT40_MODE(cm->mode) && (rd == &rd5GHz)) {
828 chanSep = 40;
829 if (fband->lowChannel == 5280)
830 low_adj += 20;
831
832 if (fband->lowChannel == 5170)
833 continue;
834 } else
835 chanSep = fband->channelSep;
836
837 for (c = fband->lowChannel + low_adj;
838 ((c <= (fband->highChannel + hi_adj)) &&
839 (c >= (fband->lowChannel + low_adj)));
840 c += chanSep) {
841 if (next >= maxchans) {
842 DPRINTF(ah->ah_sc,
843 ATH_DBG_REGULATORY,
844 "%s: too many channels "
845 "for channel table\n",
846 __func__);
847 goto done;
848 }
849 if (ath9k_regd_add_channel(ah,
850 c, c_lo, c_hi,
851 maxChan, ctl,
852 next,
853 rd5GHz,
854 fband, rd, cm,
855 ichans,
856 enableExtendedChannels))
857 next++;
858 }
859 if (IS_HT40_MODE(cm->mode) &&
860 (fband->lowChannel == 5280)) {
861 low_adj -= 20;
862 }
863 }
864 }
865 }
866 done:
867 if (next != 0) {
868 int i;
869
870 if (next > ARRAY_SIZE(ah->ah_channels)) {
871 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
872 "%s: too many channels %u; truncating to %u\n",
873 __func__, next,
874 (int) ARRAY_SIZE(ah->ah_channels));
875 next = ARRAY_SIZE(ah->ah_channels);
876 }
877 #ifdef ATH_NF_PER_CHAN
878 ath9k_regd_init_rf_buffer(ichans, next);
879 #endif
880 ath9k_regd_sort(ichans, next,
881 sizeof(struct ath9k_channel),
882 ath9k_regd_chansort);
883
884 ah->ah_nchan = next;
885
886 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "Channel list:\n");
887 for (i = 0; i < next; i++) {
888 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
889 "chan: %d flags: 0x%x\n",
890 ah->ah_channels[i].channel,
891 ah->ah_channels[i].channelFlags);
892 }
893 }
894 *nchans = next;
895
896 ah->ah_countryCode = ah->ah_countryCode;
897
898 ah->ah_currentRDInUse = regdmn;
899 ah->ah_currentRD5G = rd5GHz.regDmnEnum;
900 ah->ah_currentRD2G = rd2GHz.regDmnEnum;
901 if (country == NULL) {
902 ah->ah_iso[0] = 0;
903 ah->ah_iso[1] = 0;
904 } else {
905 ah->ah_iso[0] = country->isoName[0];
906 ah->ah_iso[1] = country->isoName[1];
907 }
908
909 return next != 0;
910 }
911
912 struct ath9k_channel*
913 ath9k_regd_check_channel(struct ath_hal *ah,
914 const struct ath9k_channel *c)
915 {
916 struct ath9k_channel *base, *cc;
917
918 int flags = c->channelFlags & CHAN_FLAGS;
919 int n, lim;
920
921 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
922 "%s: channel %u/0x%x (0x%x) requested\n", __func__,
923 c->channel, c->channelFlags, flags);
924
925 cc = ah->ah_curchan;
926 if (cc != NULL && cc->channel == c->channel &&
927 (cc->channelFlags & CHAN_FLAGS) == flags) {
928 if ((cc->privFlags & CHANNEL_INTERFERENCE) &&
929 (cc->privFlags & CHANNEL_DFS))
930 return NULL;
931 else
932 return cc;
933 }
934
935 base = ah->ah_channels;
936 n = ah->ah_nchan;
937
938 for (lim = n; lim != 0; lim >>= 1) {
939 int d;
940 cc = &base[lim >> 1];
941 d = c->channel - cc->channel;
942 if (d == 0) {
943 if ((cc->channelFlags & CHAN_FLAGS) == flags) {
944 if ((cc->privFlags & CHANNEL_INTERFERENCE) &&
945 (cc->privFlags & CHANNEL_DFS))
946 return NULL;
947 else
948 return cc;
949 }
950 d = flags - (cc->channelFlags & CHAN_FLAGS);
951 }
952 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
953 "%s: channel %u/0x%x d %d\n", __func__,
954 cc->channel, cc->channelFlags, d);
955 if (d > 0) {
956 base = cc + 1;
957 lim--;
958 }
959 }
960 DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: no match for %u/0x%x\n",
961 __func__, c->channel, c->channelFlags);
962 return NULL;
963 }
964
965 u32
966 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
967 struct ath9k_channel *chan)
968 {
969 struct ath9k_channel *ichan = NULL;
970
971 ichan = ath9k_regd_check_channel(ah, chan);
972 if (!ichan)
973 return 0;
974
975 return ichan->antennaMax;
976 }
977
978 u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan)
979 {
980 u32 ctl = NO_CTL;
981 struct ath9k_channel *ichan;
982
983 if (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)) {
984 if (IS_CHAN_B(chan))
985 ctl = SD_NO_CTL | CTL_11B;
986 else if (IS_CHAN_G(chan))
987 ctl = SD_NO_CTL | CTL_11G;
988 else
989 ctl = SD_NO_CTL | CTL_11A;
990 } else {
991 ichan = ath9k_regd_check_channel(ah, chan);
992 if (ichan != NULL) {
993 /* FIXME */
994 if (IS_CHAN_A(ichan))
995 ctl = ichan->conformanceTestLimit[0];
996 else if (IS_CHAN_B(ichan))
997 ctl = ichan->conformanceTestLimit[1];
998 else if (IS_CHAN_G(ichan))
999 ctl = ichan->conformanceTestLimit[2];
1000
1001 if (IS_CHAN_G(chan) && (ctl & 0xf) == CTL_11B)
1002 ctl = (ctl & ~0xf) | CTL_11G;
1003 }
1004 }
1005 return ctl;
1006 }
1007
1008 void ath9k_regd_get_current_country(struct ath_hal *ah,
1009 struct ath9k_country_entry *ctry)
1010 {
1011 u16 rd = ath9k_regd_get_eepromRD(ah);
1012
1013 ctry->isMultidomain = false;
1014 if (rd == CTRY_DEFAULT)
1015 ctry->isMultidomain = true;
1016 else if (!(rd & COUNTRY_ERD_FLAG))
1017 ctry->isMultidomain = isWwrSKU(ah);
1018
1019 ctry->countryCode = ah->ah_countryCode;
1020 ctry->regDmnEnum = ah->ah_currentRD;
1021 ctry->regDmn5G = ah->ah_currentRD5G;
1022 ctry->regDmn2G = ah->ah_currentRD2G;
1023 ctry->iso[0] = ah->ah_iso[0];
1024 ctry->iso[1] = ah->ah_iso[1];
1025 ctry->iso[2] = ah->ah_iso[2];
1026 }
This page took 0.139487 seconds and 6 git commands to generate.