1 /* 2 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3 * Copyright (c) 2005-2006 Atheros Communications, Inc. 4 * All rights reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $FreeBSD$ 19 */ 20 #include "opt_ah.h" 21 22 #include "ah.h" 23 24 #include <net80211/_ieee80211.h> 25 #include <net80211/ieee80211_regdomain.h> 26 27 #include "ah_internal.h" 28 #include "ah_eeprom.h" 29 #include "ah_devid.h" 30 31 #include "ah_regdomain.h" 32 33 /* 34 * XXX this code needs a audit+review 35 */ 36 37 /* used throughout this file... */ 38 #define N(a) (sizeof (a) / sizeof (a[0])) 39 40 #define HAL_MODE_11A_TURBO HAL_MODE_108A 41 #define HAL_MODE_11G_TURBO HAL_MODE_108G 42 43 /* 44 * Mask to check whether a domain is a multidomain or a single domain 45 */ 46 #define MULTI_DOMAIN_MASK 0xFF00 47 48 /* 49 * Enumerated Regulatory Domain Information 8 bit values indicate that 50 * the regdomain is really a pair of unitary regdomains. 12 bit values 51 * are the real unitary regdomains and are the only ones which have the 52 * frequency bitmasks and flags set. 53 */ 54 #include "ah_regdomain/ah_rd_regenum.h" 55 56 #define WORLD_SKU_MASK 0x00F0 57 #define WORLD_SKU_PREFIX 0x0060 58 59 /* 60 * THE following table is the mapping of regdomain pairs specified by 61 * an 8 bit regdomain value to the individual unitary reg domains 62 */ 63 #include "ah_regdomain/ah_rd_regmap.h" 64 65 /* 66 * The following tables are the master list for all different freqeuncy 67 * bands with the complete matrix of all possible flags and settings 68 * for each band if it is used in ANY reg domain. 69 */ 70 71 #define COUNTRY_ERD_FLAG 0x8000 72 #define WORLDWIDE_ROAMING_FLAG 0x4000 73 74 /* 75 * This table maps country ISO codes from net80211 into regulatory 76 * domains which the ath regulatory domain code understands. 77 */ 78 #include "ah_regdomain/ah_rd_ctry.h" 79 80 /* 81 * The frequency band collections are a set of frequency ranges 82 * with shared properties - max tx power, max antenna gain, channel width, 83 * channel spacing, DFS requirements and passive scanning requirements. 84 * 85 * These are represented as entries in a frequency band bitmask. 86 * Each regulatory domain entry in ah_regdomain_domains.h uses one 87 * or more frequency band entries for each of the channel modes 88 * supported (11bg, 11a, half, quarter, turbo, etc.) 89 * 90 */ 91 #include "ah_regdomain/ah_rd_freqbands.h" 92 93 /* 94 * This is the main regulatory database. It defines the supported 95 * set of features and requirements for each of the defined regulatory 96 * zones. It uses combinations of frequency ranges - represented in 97 * a bitmask - to determine the requirements and limitations needed. 98 */ 99 #include "ah_regdomain/ah_rd_domains.h" 100 101 static const struct cmode modes[] = { 102 { HAL_MODE_TURBO, IEEE80211_CHAN_ST }, 103 { HAL_MODE_11A, IEEE80211_CHAN_A }, 104 { HAL_MODE_11B, IEEE80211_CHAN_B }, 105 { HAL_MODE_11G, IEEE80211_CHAN_G }, 106 { HAL_MODE_11G_TURBO, IEEE80211_CHAN_108G }, 107 { HAL_MODE_11A_TURBO, IEEE80211_CHAN_108A }, 108 { HAL_MODE_11A_QUARTER_RATE, 109 IEEE80211_CHAN_A | IEEE80211_CHAN_QUARTER }, 110 { HAL_MODE_11A_HALF_RATE, 111 IEEE80211_CHAN_A | IEEE80211_CHAN_HALF }, 112 { HAL_MODE_11G_QUARTER_RATE, 113 IEEE80211_CHAN_G | IEEE80211_CHAN_QUARTER }, 114 { HAL_MODE_11G_HALF_RATE, 115 IEEE80211_CHAN_G | IEEE80211_CHAN_HALF }, 116 { HAL_MODE_11NG_HT20, IEEE80211_CHAN_G | IEEE80211_CHAN_HT20 }, 117 { HAL_MODE_11NG_HT40PLUS, 118 IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U }, 119 { HAL_MODE_11NG_HT40MINUS, 120 IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D }, 121 { HAL_MODE_11NA_HT20, IEEE80211_CHAN_A | IEEE80211_CHAN_HT20 }, 122 { HAL_MODE_11NA_HT40PLUS, 123 IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U }, 124 { HAL_MODE_11NA_HT40MINUS, 125 IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D }, 126 }; 127 128 static void ath_hal_update_dfsdomain(struct ath_hal *ah); 129 130 static OS_INLINE uint16_t 131 getEepromRD(struct ath_hal *ah) 132 { 133 return AH_PRIVATE(ah)->ah_currentRD &~ WORLDWIDE_ROAMING_FLAG; 134 } 135 136 /* 137 * Test to see if the bitmask array is all zeros 138 */ 139 static HAL_BOOL 140 isChanBitMaskZero(const uint64_t *bitmask) 141 { 142 #if BMLEN > 2 143 #error "add more cases" 144 #endif 145 #if BMLEN > 1 146 if (bitmask[1] != 0) 147 return AH_FALSE; 148 #endif 149 return (bitmask[0] == 0); 150 } 151 152 /* 153 * Return whether or not the regulatory domain/country in EEPROM 154 * is acceptable. 155 */ 156 static HAL_BOOL 157 isEepromValid(struct ath_hal *ah) 158 { 159 uint16_t rd = getEepromRD(ah); 160 int i; 161 162 if (rd & COUNTRY_ERD_FLAG) { 163 uint16_t cc = rd &~ COUNTRY_ERD_FLAG; 164 for (i = 0; i < N(allCountries); i++) 165 if (allCountries[i].countryCode == cc) 166 return AH_TRUE; 167 } else { 168 for (i = 0; i < N(regDomainPairs); i++) 169 if (regDomainPairs[i].regDmnEnum == rd) 170 return AH_TRUE; 171 } 172 173 if (rd == FCC_UBNT) { 174 return AH_TRUE; 175 } 176 177 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 178 "%s: invalid regulatory domain/country code 0x%x\n", __func__, rd); 179 return AH_FALSE; 180 } 181 182 /* 183 * Find the pointer to the country element in the country table 184 * corresponding to the country code 185 */ 186 static COUNTRY_CODE_TO_ENUM_RD* 187 findCountry(HAL_CTRY_CODE countryCode) 188 { 189 int i; 190 191 for (i = 0; i < N(allCountries); i++) { 192 if (allCountries[i].countryCode == countryCode) 193 return &allCountries[i]; 194 } 195 return AH_NULL; 196 } 197 198 static REG_DOMAIN * 199 findRegDmn(int regDmn) 200 { 201 int i; 202 203 for (i = 0; i < N(regDomains); i++) { 204 if (regDomains[i].regDmnEnum == regDmn) 205 return ®Domains[i]; 206 } 207 return AH_NULL; 208 } 209 210 static REG_DMN_PAIR_MAPPING * 211 findRegDmnPair(int regDmnPair) 212 { 213 int i; 214 215 if (regDmnPair != NO_ENUMRD) { 216 for (i = 0; i < N(regDomainPairs); i++) { 217 if (regDomainPairs[i].regDmnEnum == regDmnPair) 218 return ®DomainPairs[i]; 219 } 220 } 221 return AH_NULL; 222 } 223 224 /* 225 * Calculate a default country based on the EEPROM setting. 226 */ 227 static HAL_CTRY_CODE 228 getDefaultCountry(struct ath_hal *ah) 229 { 230 REG_DMN_PAIR_MAPPING *regpair; 231 uint16_t rd; 232 233 rd = getEepromRD(ah); 234 if (rd & COUNTRY_ERD_FLAG) { 235 COUNTRY_CODE_TO_ENUM_RD *country; 236 uint16_t cc = rd & ~COUNTRY_ERD_FLAG; 237 country = findCountry(cc); 238 if (country != AH_NULL) 239 return cc; 240 } 241 /* 242 * Check reg domains that have only one country 243 */ 244 regpair = findRegDmnPair(rd); 245 return (regpair != AH_NULL) ? regpair->singleCC : CTRY_DEFAULT; 246 } 247 248 static HAL_BOOL 249 IS_BIT_SET(int bit, const uint64_t bitmask[]) 250 { 251 int byteOffset, bitnum; 252 uint64_t val; 253 254 byteOffset = bit/64; 255 bitnum = bit - byteOffset*64; 256 val = ((uint64_t) 1) << bitnum; 257 return (bitmask[byteOffset] & val) != 0; 258 } 259 260 static HAL_STATUS 261 getregstate(struct ath_hal *ah, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn, 262 COUNTRY_CODE_TO_ENUM_RD **pcountry, 263 REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz) 264 { 265 COUNTRY_CODE_TO_ENUM_RD *country; 266 REG_DOMAIN *rd5GHz, *rd2GHz; 267 268 if (cc == CTRY_DEFAULT && regDmn == SKU_NONE) { 269 /* 270 * Validate the EEPROM setting and setup defaults 271 */ 272 if (!isEepromValid(ah)) { 273 /* 274 * Don't return any channels if the EEPROM has an 275 * invalid regulatory domain/country code setting. 276 */ 277 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 278 "%s: invalid EEPROM contents\n",__func__); 279 return HAL_EEBADREG; 280 } 281 282 cc = getDefaultCountry(ah); 283 country = findCountry(cc); 284 if (country == AH_NULL) { 285 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 286 "NULL Country!, cc %d\n", cc); 287 return HAL_EEBADCC; 288 } 289 regDmn = country->regDmnEnum; 290 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: EEPROM cc %u rd 0x%x\n", 291 __func__, cc, regDmn); 292 293 if (country->countryCode == CTRY_DEFAULT) { 294 /* 295 * Check EEPROM; SKU may be for a country, single 296 * domain, or multiple domains (WWR). 297 */ 298 uint16_t rdnum = getEepromRD(ah); 299 if ((rdnum & COUNTRY_ERD_FLAG) == 0 && 300 (findRegDmn(rdnum) != AH_NULL || 301 findRegDmnPair(rdnum) != AH_NULL)) { 302 regDmn = rdnum; 303 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 304 "%s: EEPROM rd 0x%x\n", __func__, rdnum); 305 } 306 } 307 } else { 308 country = findCountry(cc); 309 if (country == AH_NULL) { 310 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 311 "unknown country, cc %d\n", cc); 312 return HAL_EINVAL; 313 } 314 if (regDmn == SKU_NONE) 315 regDmn = country->regDmnEnum; 316 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u rd 0x%x\n", 317 __func__, cc, regDmn); 318 } 319 320 /* 321 * Setup per-band state. 322 */ 323 if ((regDmn & MULTI_DOMAIN_MASK) == 0) { 324 REG_DMN_PAIR_MAPPING *regpair = findRegDmnPair(regDmn); 325 if (regpair == AH_NULL) { 326 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 327 "%s: no reg domain pair %u for country %u\n", 328 __func__, regDmn, country->countryCode); 329 return HAL_EINVAL; 330 } 331 rd5GHz = findRegDmn(regpair->regDmn5GHz); 332 if (rd5GHz == AH_NULL) { 333 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 334 "%s: no 5GHz reg domain %u for country %u\n", 335 __func__, regpair->regDmn5GHz, country->countryCode); 336 return HAL_EINVAL; 337 } 338 rd2GHz = findRegDmn(regpair->regDmn2GHz); 339 if (rd2GHz == AH_NULL) { 340 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 341 "%s: no 2GHz reg domain %u for country %u\n", 342 __func__, regpair->regDmn2GHz, country->countryCode); 343 return HAL_EINVAL; 344 } 345 } else { 346 rd5GHz = rd2GHz = findRegDmn(regDmn); 347 if (rd2GHz == AH_NULL) { 348 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 349 "%s: no unitary reg domain %u for country %u\n", 350 __func__, regDmn, country->countryCode); 351 return HAL_EINVAL; 352 } 353 } 354 if (pcountry != AH_NULL) 355 *pcountry = country; 356 *prd2GHz = rd2GHz; 357 *prd5GHz = rd5GHz; 358 return HAL_OK; 359 } 360 361 /* 362 * Construct the channel list for the specified regulatory config. 363 */ 364 static HAL_STATUS 365 getchannels(struct ath_hal *ah, 366 struct ieee80211_channel chans[], u_int maxchans, int *nchans, 367 u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn, 368 HAL_BOOL enableExtendedChannels, 369 COUNTRY_CODE_TO_ENUM_RD **pcountry, 370 REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz) 371 { 372 #define CHANNEL_HALF_BW 10 373 #define CHANNEL_QUARTER_BW 5 374 #define HAL_MODE_11A_ALL \ 375 (HAL_MODE_11A | HAL_MODE_11A_TURBO | HAL_MODE_TURBO | \ 376 HAL_MODE_11A_QUARTER_RATE | HAL_MODE_11A_HALF_RATE) 377 REG_DOMAIN *rd5GHz, *rd2GHz; 378 u_int modesAvail; 379 const struct cmode *cm; 380 struct ieee80211_channel *ic; 381 int next, b; 382 HAL_STATUS status; 383 384 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u regDmn 0x%x mode 0x%x%s\n", 385 __func__, cc, regDmn, modeSelect, 386 enableExtendedChannels ? " ecm" : ""); 387 388 status = getregstate(ah, cc, regDmn, pcountry, &rd2GHz, &rd5GHz); 389 if (status != HAL_OK) 390 return status; 391 392 /* get modes that HW is capable of */ 393 modesAvail = ath_hal_getWirelessModes(ah); 394 /* optimize work below if no 11a channels */ 395 if (isChanBitMaskZero(rd5GHz->chan11a) && 396 (modesAvail & HAL_MODE_11A_ALL)) { 397 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 398 "%s: disallow all 11a\n", __func__); 399 modesAvail &= ~HAL_MODE_11A_ALL; 400 } 401 402 next = 0; 403 ic = &chans[0]; 404 for (cm = modes; cm < &modes[N(modes)]; cm++) { 405 uint16_t c, c_hi, c_lo; 406 uint64_t *channelBM = AH_NULL; 407 REG_DMN_FREQ_BAND *fband = AH_NULL,*freqs; 408 int low_adj, hi_adj, channelSep, lastc; 409 uint32_t rdflags; 410 uint64_t dfsMask; 411 uint64_t pscan; 412 413 if ((cm->mode & modeSelect) == 0) { 414 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 415 "%s: skip mode 0x%x flags 0x%x\n", 416 __func__, cm->mode, cm->flags); 417 continue; 418 } 419 if ((cm->mode & modesAvail) == 0) { 420 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 421 "%s: !avail mode 0x%x (0x%x) flags 0x%x\n", 422 __func__, modesAvail, cm->mode, cm->flags); 423 continue; 424 } 425 if (!ath_hal_getChannelEdges(ah, cm->flags, &c_lo, &c_hi)) { 426 /* channel not supported by hardware, skip it */ 427 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 428 "%s: channels 0x%x not supported by hardware\n", 429 __func__,cm->flags); 430 continue; 431 } 432 switch (cm->mode) { 433 case HAL_MODE_TURBO: 434 case HAL_MODE_11A_TURBO: 435 rdflags = rd5GHz->flags; 436 dfsMask = rd5GHz->dfsMask; 437 pscan = rd5GHz->pscan; 438 if (cm->mode == HAL_MODE_TURBO) 439 channelBM = rd5GHz->chan11a_turbo; 440 else 441 channelBM = rd5GHz->chan11a_dyn_turbo; 442 freqs = ®Dmn5GhzTurboFreq[0]; 443 break; 444 case HAL_MODE_11G_TURBO: 445 rdflags = rd2GHz->flags; 446 dfsMask = rd2GHz->dfsMask; 447 pscan = rd2GHz->pscan; 448 channelBM = rd2GHz->chan11g_turbo; 449 freqs = ®Dmn2Ghz11gTurboFreq[0]; 450 break; 451 case HAL_MODE_11A: 452 case HAL_MODE_11A_HALF_RATE: 453 case HAL_MODE_11A_QUARTER_RATE: 454 case HAL_MODE_11NA_HT20: 455 case HAL_MODE_11NA_HT40PLUS: 456 case HAL_MODE_11NA_HT40MINUS: 457 rdflags = rd5GHz->flags; 458 dfsMask = rd5GHz->dfsMask; 459 pscan = rd5GHz->pscan; 460 if (cm->mode == HAL_MODE_11A_HALF_RATE) 461 channelBM = rd5GHz->chan11a_half; 462 else if (cm->mode == HAL_MODE_11A_QUARTER_RATE) 463 channelBM = rd5GHz->chan11a_quarter; 464 else 465 channelBM = rd5GHz->chan11a; 466 freqs = ®Dmn5GhzFreq[0]; 467 break; 468 case HAL_MODE_11B: 469 case HAL_MODE_11G: 470 case HAL_MODE_11G_HALF_RATE: 471 case HAL_MODE_11G_QUARTER_RATE: 472 case HAL_MODE_11NG_HT20: 473 case HAL_MODE_11NG_HT40PLUS: 474 case HAL_MODE_11NG_HT40MINUS: 475 rdflags = rd2GHz->flags; 476 dfsMask = rd2GHz->dfsMask; 477 pscan = rd2GHz->pscan; 478 if (cm->mode == HAL_MODE_11G_HALF_RATE) 479 channelBM = rd2GHz->chan11g_half; 480 else if (cm->mode == HAL_MODE_11G_QUARTER_RATE) 481 channelBM = rd2GHz->chan11g_quarter; 482 else if (cm->mode == HAL_MODE_11B) 483 channelBM = rd2GHz->chan11b; 484 else 485 channelBM = rd2GHz->chan11g; 486 if (cm->mode == HAL_MODE_11B) 487 freqs = ®Dmn2GhzFreq[0]; 488 else 489 freqs = ®Dmn2Ghz11gFreq[0]; 490 break; 491 default: 492 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 493 "%s: Unknown HAL mode 0x%x\n", __func__, cm->mode); 494 continue; 495 } 496 if (isChanBitMaskZero(channelBM)) 497 continue; 498 /* 499 * Setup special handling for HT40 channels; e.g. 500 * 5G HT40 channels require 40Mhz channel separation. 501 */ 502 hi_adj = (cm->mode == HAL_MODE_11NA_HT40PLUS || 503 cm->mode == HAL_MODE_11NG_HT40PLUS) ? -20 : 0; 504 low_adj = (cm->mode == HAL_MODE_11NA_HT40MINUS || 505 cm->mode == HAL_MODE_11NG_HT40MINUS) ? 20 : 0; 506 channelSep = (cm->mode == HAL_MODE_11NA_HT40PLUS || 507 cm->mode == HAL_MODE_11NA_HT40MINUS) ? 40 : 0; 508 509 for (b = 0; b < 64*BMLEN; b++) { 510 if (!IS_BIT_SET(b, channelBM)) 511 continue; 512 fband = &freqs[b]; 513 lastc = 0; 514 515 for (c = fband->lowChannel + low_adj; 516 c <= fband->highChannel + hi_adj; 517 c += fband->channelSep) { 518 if (!(c_lo <= c && c <= c_hi)) { 519 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 520 "%s: c %u out of range [%u..%u]\n", 521 __func__, c, c_lo, c_hi); 522 continue; 523 } 524 if (next >= maxchans){ 525 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 526 "%s: too many channels for channel table\n", 527 __func__); 528 goto done; 529 } 530 if ((fband->usePassScan & IS_ECM_CHAN) && 531 !enableExtendedChannels) { 532 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 533 "skip ecm channel\n"); 534 continue; 535 } 536 #if 0 537 if ((fband->useDfs & dfsMask) && 538 (cm->flags & IEEE80211_CHAN_HT40)) { 539 /* NB: DFS and HT40 don't mix */ 540 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 541 "skip HT40 chan, DFS required\n"); 542 continue; 543 } 544 #endif 545 /* 546 * Make sure that channel separation 547 * meets the requirement. 548 */ 549 if (lastc && channelSep && 550 (c-lastc) < channelSep) 551 continue; 552 lastc = c; 553 554 OS_MEMZERO(ic, sizeof(*ic)); 555 ic->ic_freq = c; 556 ic->ic_flags = cm->flags; 557 ic->ic_maxregpower = fband->powerDfs; 558 ath_hal_getpowerlimits(ah, ic); 559 ic->ic_maxantgain = fband->antennaMax; 560 if (fband->usePassScan & pscan) 561 ic->ic_flags |= IEEE80211_CHAN_PASSIVE; 562 if (fband->useDfs & dfsMask) 563 ic->ic_flags |= IEEE80211_CHAN_DFS; 564 if (IEEE80211_IS_CHAN_5GHZ(ic) && 565 (rdflags & DISALLOW_ADHOC_11A)) 566 ic->ic_flags |= IEEE80211_CHAN_NOADHOC; 567 if (IEEE80211_IS_CHAN_TURBO(ic) && 568 (rdflags & DISALLOW_ADHOC_11A_TURB)) 569 ic->ic_flags |= IEEE80211_CHAN_NOADHOC; 570 if (rdflags & NO_HOSTAP) 571 ic->ic_flags |= IEEE80211_CHAN_NOHOSTAP; 572 if (rdflags & LIMIT_FRAME_4MS) 573 ic->ic_flags |= IEEE80211_CHAN_4MSXMIT; 574 if (rdflags & NEED_NFC) 575 ic->ic_flags |= CHANNEL_NFCREQUIRED; 576 577 ic++, next++; 578 } 579 } 580 } 581 done: 582 *nchans = next; 583 /* NB: pcountry set above by getregstate */ 584 if (prd2GHz != AH_NULL) 585 *prd2GHz = rd2GHz; 586 if (prd5GHz != AH_NULL) 587 *prd5GHz = rd5GHz; 588 return HAL_OK; 589 #undef HAL_MODE_11A_ALL 590 #undef CHANNEL_HALF_BW 591 #undef CHANNEL_QUARTER_BW 592 } 593 594 /* 595 * Retrieve a channel list without affecting runtime state. 596 */ 597 HAL_STATUS 598 ath_hal_getchannels(struct ath_hal *ah, 599 struct ieee80211_channel chans[], u_int maxchans, int *nchans, 600 u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn, 601 HAL_BOOL enableExtendedChannels) 602 { 603 return getchannels(ah, chans, maxchans, nchans, modeSelect, 604 cc, regDmn, enableExtendedChannels, AH_NULL, AH_NULL, AH_NULL); 605 } 606 607 /* 608 * Handle frequency mapping from 900Mhz range to 2.4GHz range 609 * for GSM radios. This is done when we need the h/w frequency 610 * and the channel is marked IEEE80211_CHAN_GSM. 611 */ 612 static int 613 ath_hal_mapgsm(int sku, int freq) 614 { 615 if (sku == SKU_XR9) 616 return 1520 + freq; 617 if (sku == SKU_GZ901) 618 return 1544 + freq; 619 if (sku == SKU_SR9) 620 return 3344 - freq; 621 if (sku == SKU_XC900M) 622 return 1517 + freq; 623 HALDEBUG(AH_NULL, HAL_DEBUG_ANY, 624 "%s: cannot map freq %u unknown gsm sku %u\n", 625 __func__, freq, sku); 626 return freq; 627 } 628 629 /* 630 * Setup the internal/private channel state given a table of 631 * net80211 channels. We collapse entries for the same frequency 632 * and record the frequency for doing noise floor processing 633 * where we don't have net80211 channel context. 634 */ 635 static HAL_BOOL 636 assignPrivateChannels(struct ath_hal *ah, 637 struct ieee80211_channel chans[], int nchans, int sku) 638 { 639 HAL_CHANNEL_INTERNAL *ic; 640 int i, j, next, freq; 641 642 next = 0; 643 for (i = 0; i < nchans; i++) { 644 struct ieee80211_channel *c = &chans[i]; 645 for (j = i-1; j >= 0; j--) 646 if (chans[j].ic_freq == c->ic_freq) { 647 c->ic_devdata = chans[j].ic_devdata; 648 break; 649 } 650 if (j < 0) { 651 /* new entry, assign a private channel entry */ 652 if (next >= N(AH_PRIVATE(ah)->ah_channels)) { 653 HALDEBUG(ah, HAL_DEBUG_ANY, 654 "%s: too many channels, max %zu\n", 655 __func__, N(AH_PRIVATE(ah)->ah_channels)); 656 return AH_FALSE; 657 } 658 /* 659 * Handle frequency mapping for 900MHz devices. 660 * The hardware uses 2.4GHz frequencies that are 661 * down-converted. The 802.11 layer uses the 662 * true frequencies. 663 */ 664 freq = IEEE80211_IS_CHAN_GSM(c) ? 665 ath_hal_mapgsm(sku, c->ic_freq) : c->ic_freq; 666 667 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, 668 "%s: private[%3u] %u/0x%x -> channel %u\n", 669 __func__, next, c->ic_freq, c->ic_flags, freq); 670 671 ic = &AH_PRIVATE(ah)->ah_channels[next]; 672 /* 673 * NB: This clears privFlags which means ancillary 674 * code like ANI and IQ calibration will be 675 * restarted and re-setup any per-channel state. 676 */ 677 OS_MEMZERO(ic, sizeof(*ic)); 678 ic->channel = freq; 679 c->ic_devdata = next; 680 next++; 681 } 682 } 683 AH_PRIVATE(ah)->ah_nchan = next; 684 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: %u public, %u private channels\n", 685 __func__, nchans, next); 686 return AH_TRUE; 687 } 688 689 /* 690 * Setup the channel list based on the information in the EEPROM. 691 */ 692 HAL_STATUS 693 ath_hal_init_channels(struct ath_hal *ah, 694 struct ieee80211_channel chans[], u_int maxchans, int *nchans, 695 u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn, 696 HAL_BOOL enableExtendedChannels) 697 { 698 COUNTRY_CODE_TO_ENUM_RD *country; 699 REG_DOMAIN *rd5GHz, *rd2GHz; 700 HAL_STATUS status; 701 702 status = getchannels(ah, chans, maxchans, nchans, modeSelect, 703 cc, regDmn, enableExtendedChannels, &country, &rd2GHz, &rd5GHz); 704 if (status == HAL_OK && 705 assignPrivateChannels(ah, chans, *nchans, AH_PRIVATE(ah)->ah_currentRD)) { 706 AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz; 707 AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz; 708 709 ah->ah_countryCode = country->countryCode; 710 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n", 711 __func__, ah->ah_countryCode); 712 713 /* Update current DFS domain */ 714 ath_hal_update_dfsdomain(ah); 715 } else 716 status = HAL_EINVAL; 717 718 return status; 719 } 720 721 /* 722 * Set the channel list. 723 */ 724 HAL_STATUS 725 ath_hal_set_channels(struct ath_hal *ah, 726 struct ieee80211_channel chans[], int nchans, 727 HAL_CTRY_CODE cc, HAL_REG_DOMAIN rd) 728 { 729 COUNTRY_CODE_TO_ENUM_RD *country; 730 REG_DOMAIN *rd5GHz, *rd2GHz; 731 HAL_STATUS status; 732 733 switch (rd) { 734 case SKU_SR9: 735 case SKU_XR9: 736 case SKU_GZ901: 737 case SKU_XC900M: 738 /* 739 * Map 900MHz sku's. The frequencies will be mapped 740 * according to the sku to compensate for the down-converter. 741 * We use the FCC for these sku's as the mapped channel 742 * list is known compatible (will need to change if/when 743 * vendors do different mapping in different locales). 744 */ 745 status = getregstate(ah, CTRY_DEFAULT, SKU_FCC, 746 &country, &rd2GHz, &rd5GHz); 747 break; 748 default: 749 status = getregstate(ah, cc, rd, 750 &country, &rd2GHz, &rd5GHz); 751 rd = AH_PRIVATE(ah)->ah_currentRD; 752 break; 753 } 754 if (status == HAL_OK && assignPrivateChannels(ah, chans, nchans, rd)) { 755 AH_PRIVATE(ah)->ah_rd2GHz = rd2GHz; 756 AH_PRIVATE(ah)->ah_rd5GHz = rd5GHz; 757 758 ah->ah_countryCode = country->countryCode; 759 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u\n", 760 __func__, ah->ah_countryCode); 761 } else 762 status = HAL_EINVAL; 763 764 if (status == HAL_OK) { 765 /* Update current DFS domain */ 766 (void) ath_hal_update_dfsdomain(ah); 767 } 768 return status; 769 } 770 771 #ifdef AH_DEBUG 772 /* 773 * Return the internal channel corresponding to a public channel. 774 * NB: normally this routine is inline'd (see ah_internal.h) 775 */ 776 HAL_CHANNEL_INTERNAL * 777 ath_hal_checkchannel(struct ath_hal *ah, const struct ieee80211_channel *c) 778 { 779 HAL_CHANNEL_INTERNAL *cc = &AH_PRIVATE(ah)->ah_channels[c->ic_devdata]; 780 781 if (c->ic_devdata < AH_PRIVATE(ah)->ah_nchan && 782 (c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c))) 783 return cc; 784 if (c->ic_devdata >= AH_PRIVATE(ah)->ah_nchan) { 785 HALDEBUG(ah, HAL_DEBUG_ANY, 786 "%s: bad mapping, devdata %u nchans %u\n", 787 __func__, c->ic_devdata, AH_PRIVATE(ah)->ah_nchan); 788 HALASSERT(c->ic_devdata < AH_PRIVATE(ah)->ah_nchan); 789 } else { 790 HALDEBUG(ah, HAL_DEBUG_ANY, 791 "%s: no match for %u/0x%x devdata %u channel %u\n", 792 __func__, c->ic_freq, c->ic_flags, c->ic_devdata, 793 cc->channel); 794 HALASSERT(c->ic_freq == cc->channel || IEEE80211_IS_CHAN_GSM(c)); 795 } 796 return AH_NULL; 797 } 798 #endif /* AH_DEBUG */ 799 800 #define isWwrSKU(_ah) \ 801 ((getEepromRD((_ah)) & WORLD_SKU_MASK) == WORLD_SKU_PREFIX || \ 802 getEepromRD(_ah) == WORLD) 803 804 /* 805 * Return the test group for the specific channel based on 806 * the current regulatory setup. 807 */ 808 u_int 809 ath_hal_getctl(struct ath_hal *ah, const struct ieee80211_channel *c) 810 { 811 u_int ctl; 812 813 if (AH_PRIVATE(ah)->ah_rd2GHz == AH_PRIVATE(ah)->ah_rd5GHz || 814 (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah))) 815 ctl = SD_NO_CTL; 816 else if (IEEE80211_IS_CHAN_2GHZ(c)) 817 ctl = AH_PRIVATE(ah)->ah_rd2GHz->conformanceTestLimit; 818 else 819 ctl = AH_PRIVATE(ah)->ah_rd5GHz->conformanceTestLimit; 820 if (IEEE80211_IS_CHAN_B(c)) 821 return ctl | CTL_11B; 822 if (IEEE80211_IS_CHAN_G(c)) 823 return ctl | CTL_11G; 824 if (IEEE80211_IS_CHAN_108G(c)) 825 return ctl | CTL_108G; 826 if (IEEE80211_IS_CHAN_TURBO(c)) 827 return ctl | CTL_TURBO; 828 if (IEEE80211_IS_CHAN_A(c)) 829 return ctl | CTL_11A; 830 return ctl; 831 } 832 833 834 /* 835 * Update the current dfsDomain setting based on the given 836 * country code. 837 * 838 * Since FreeBSD/net80211 allows the channel set to change 839 * after the card has been setup (via ath_hal_init_channels()) 840 * this function method is needed to update ah_dfsDomain. 841 */ 842 void 843 ath_hal_update_dfsdomain(struct ath_hal *ah) 844 { 845 const REG_DOMAIN *rd5GHz = AH_PRIVATE(ah)->ah_rd5GHz; 846 HAL_DFS_DOMAIN dfsDomain = HAL_DFS_UNINIT_DOMAIN; 847 848 if (rd5GHz->dfsMask & DFS_FCC3) 849 dfsDomain = HAL_DFS_FCC_DOMAIN; 850 if (rd5GHz->dfsMask & DFS_ETSI) 851 dfsDomain = HAL_DFS_ETSI_DOMAIN; 852 if (rd5GHz->dfsMask & DFS_MKK4) 853 dfsDomain = HAL_DFS_MKK4_DOMAIN; 854 AH_PRIVATE(ah)->ah_dfsDomain = dfsDomain; 855 HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s ah_dfsDomain: %d\n", 856 __func__, AH_PRIVATE(ah)->ah_dfsDomain); 857 } 858 859 860 /* 861 * Return the max allowed antenna gain and apply any regulatory 862 * domain specific changes. 863 * 864 * NOTE: a negative reduction is possible in RD's that only 865 * measure radiated power (e.g., ETSI) which would increase 866 * that actual conducted output power (though never beyond 867 * the calibrated target power). 868 */ 869 u_int 870 ath_hal_getantennareduction(struct ath_hal *ah, 871 const struct ieee80211_channel *chan, u_int twiceGain) 872 { 873 int8_t antennaMax = twiceGain - chan->ic_maxantgain*2; 874 return (antennaMax < 0) ? 0 : antennaMax; 875 } 876