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 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 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 54 ath9k_regd_get_eepromRD(struct ath_hal *ah) 55 { 56 return (ah->ah_currentRD & ~WORLDWIDE_ROAMING_FLAG); 57 } 58 59 static boolean_t 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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