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