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